Package de.innovationgate.wgpublisher

Source Code of de.innovationgate.wgpublisher.WGPDispatcher$TemporaryDownload

/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.SocketException;
import java.net.URL;
import java.net.URLDecoder;
import java.rmi.RemoteException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.activation.DataSource;
import javax.activation.URLDataSource;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionBindingListener;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.Logger;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentFactory;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.DOMWriter;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.jdom.IllegalDataException;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.Dom4JDriver;

import de.innovationgate.utils.Base64;
import de.innovationgate.utils.TemporaryFile;
import de.innovationgate.utils.TransientList;
import de.innovationgate.utils.TransientMap;
import de.innovationgate.utils.UIDGenerator;
import de.innovationgate.utils.URLBuilder;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.utils.Zipper;
import de.innovationgate.utils.io.ByteArrayDataSource;

import de.innovationgate.webgate.api.WGACLEntry;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGCSSJSModule;
import de.innovationgate.webgate.api.WGContent;
import de.innovationgate.webgate.api.WGContentKey;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.webgate.api.WGIllegalArgumentException;
import de.innovationgate.webgate.api.WGLanguage;
import de.innovationgate.webgate.api.WGLanguageChooser;
import de.innovationgate.webgate.api.WGScriptModule;
import de.innovationgate.webgate.api.WGStructEntry;
import de.innovationgate.webgate.api.WGTMLModule;
import de.innovationgate.webgate.api.WGUnavailableException;
import de.innovationgate.webgate.api.WGUserProfile;
import de.innovationgate.webgate.api.jdbc.ACLEntry;
import de.innovationgate.webgate.api.utils.MasterSessionTask;
import de.innovationgate.wga.common.Constants;
import de.innovationgate.wga.common.beans.csconfig.v1.MediaKey;
import de.innovationgate.wga.common.beans.csconfig.v1.PublisherOption;
import de.innovationgate.wga.config.PersonalisationConfiguration;
import de.innovationgate.wga.model.BrowsingSecurity;
import de.innovationgate.wga.modules.ModuleDefinition;
import de.innovationgate.wga.modules.options.OptionConversionException;
import de.innovationgate.wga.modules.options.OptionDefinition;
import de.innovationgate.wga.modules.options.OptionReader;
import de.innovationgate.wga.modules.types.ContentStorePublisherOptionsModuleType;
import de.innovationgate.wga.modules.types.WGAServerOptionsModuleType;
import de.innovationgate.wgpublisher.WGACore.UserAgentVerifier;
import de.innovationgate.wgpublisher.WGACore.WGAConfigurationOptionReader;

import de.innovationgate.wgpublisher.cache.FileCache;
import de.innovationgate.wgpublisher.lang.LanguageBehaviour;
import de.innovationgate.wgpublisher.lang.LanguageBehaviourTools;
import de.innovationgate.wgpublisher.lang.RequestLanguageChooser;
import de.innovationgate.wgpublisher.lang.WebTMLLanguageChooser;
import de.innovationgate.wgpublisher.log.WGALoggerWrapper;
import de.innovationgate.wgpublisher.log.WGARequestInformation;
import de.innovationgate.wgpublisher.lucene.LuceneManager;
import de.innovationgate.wgpublisher.modules.poptions.ContentStorePublisherOptionsCollector;
import de.innovationgate.wgpublisher.modules.serveroptions.VariousModuleDefinition;
import de.innovationgate.wgpublisher.plugins.WGAPlugin;
import de.innovationgate.wgpublisher.scheduler.Job;
import de.innovationgate.wgpublisher.url.TitlePathManager;
import de.innovationgate.wgpublisher.url.WGAURLBuilder;
import de.innovationgate.wgpublisher.url.TitlePathManager.RemainingPathElementException;
import de.innovationgate.wgpublisher.url.TitlePathManager.TitlePath;
import de.innovationgate.wgpublisher.webtml.utils.AjaxActionDefinition;
import de.innovationgate.wgpublisher.webtml.utils.AjaxInfo;
import de.innovationgate.wgpublisher.webtml.utils.HttpErrorException;
import de.innovationgate.wgpublisher.webtml.utils.TMLUserProfile;

public class WGPDispatcher extends HttpServlet {

    private static final String BYTERANGE_BOUNDARY = "##BYTERANGE##";

    public static final String COOKIE_WGPID = "WGPID";

    public static final String COOKIE_SECURE_WGPID = "SecureWGPID";

    public static final String REQUESTTYPE_TML = "tml";

    public static final String REQUESTTYPE_STATICTML = "statictml";

    private static final Pattern ACCEPT_RANGE_PATTERN = Pattern.compile("(\\d+)?\\-(\\d+)?");

    private static class AcceptRange {
        public int from;

        int to;

        public AcceptRange(int from, int to) {
            this.from = from;
            this.to = to;
        }
    }

    public static class URLID {

        private String _resourceId = null;

        private String _language = null;

        private String _suffix = null;

        private String _completeId;

        private boolean _completeFormat = true;

        private WGDatabase _db;
       
        public URLID(String id, WGDatabase contentDb) throws WGAPIException {

            _db = contentDb;

            if (id == null || id.trim().equals("")) {
                throw new WGIllegalArgumentException("The given id is empty or null");
            }

            List tokens = WGUtils.deserializeCollection(id, WGContentKey.TOKEN_DIVIDER);
            Collections.reverse(tokens);
            if (tokens.size() < 3) {
                _completeFormat = false;
            }

            int contentStartsAt = 0;
            if (tokens.size() >= 2) {
                _suffix = (String) tokens.get(0);
                contentStartsAt = 1;
            }

            if (tokens.size() >= 3) {
                _language = (String) tokens.get(1);
                contentStartsAt = 2;
                if (_language.equals(DEFAULT_LANGUAGE_TOKEN)) {
                    _language = contentDb.getDefaultLanguage();
                }
            }

            List contentIdTokens = tokens.subList(contentStartsAt, tokens.size());
            Collections.reverse(contentIdTokens);
            _resourceId = WGUtils.serializeCollection(contentIdTokens, WGContentKey.TOKEN_DIVIDER);

            StringBuffer completeId = new StringBuffer();
            completeId.append(_resourceId);
            if (_language != null) {
                completeId.append(".");
                completeId.append(_language);
            }
            if (_suffix != null) {
                completeId.append(".");
                completeId.append(_suffix);
            }
            _completeId = completeId.toString();

        }

        public boolean isCompleteFormat() {
            return _completeFormat;
        }

        public void setCompleteFormat(boolean complete) {
            _completeFormat = complete;
        }

        public String getResourceId() {
            return _resourceId;
        }

        public String getLanguage() {
            return _language;
        }

        public String getSuffix() {
            return _suffix;
        }

        public String getCompleteId() {
            return _completeId;
        }

        public WGContentKey asContentKey() throws WGAPIException {
            if (isCompleteFormat()) {
                return WGContentKey.parse(_completeId, _db);
            }
            else {
                return null;
            }
        }

        public int getSuffixVersion() {

            int version = 0;
            try {
                version = Integer.parseInt(_suffix);
            }
            catch (NumberFormatException e) {
                // Everything ok. All non-numeric versions (p, mediakey) will
                // get parsed as version 0
            }
            return version;

        }

        @Override
        public String toString() {
            return _completeId;
        }

    }

    public class WebTMLDebugger {

        private Transformer _debugModulesTransformer;

        private Transformer _debugTagsTransformer = null;

        private Transformer getDebugModulesTransformer(boolean throwAway) throws TransformerConfigurationException, TransformerFactoryConfigurationError {

            if (_debugModulesTransformer == null || throwAway) {
                _debugModulesTransformer = TransformerFactory.newInstance().newTransformer(new StreamSource(getServletContext().getResourceAsStream("/tmldebugModules.xsl")));
            }
            return _debugModulesTransformer;
        }

        private Transformer getDebugTagsTransformer(boolean throwAway) throws TransformerConfigurationException, TransformerFactoryConfigurationError {

            if (_debugTagsTransformer == null || throwAway) {
                _debugTagsTransformer = TransformerFactory.newInstance().newTransformer(new StreamSource(getServletContext().getResourceAsStream("/tmlDebugTags.xsl")));
            }
            return _debugTagsTransformer;
        }

        /**
         * @param request
         * @param response
         * @param session
         * @throws HttpErrorException
         * @throws IOException
         * @throws ServletException
         */
        private void performDebugMode(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws HttpErrorException, ServletException, IOException {

            if (!getCore().isAdminLoggedIn(request)) {
                throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "You must be logged in to the wga admin page to use WebTML debugging", null);
            }

            String command = request.getParameter("command");
            Boolean debugModeEnabled = (Boolean) session.getAttribute(WGACore.ATTRIB_TMLDEBUG);
            if (debugModeEnabled == null) {
                debugModeEnabled = new Boolean(false);
            }
            Boolean resultTracingEnabled = (Boolean) session.getAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_RESULTS);
            if (resultTracingEnabled == null) {
                resultTracingEnabled = new Boolean(false);
            }

            Boolean optionsTracingEnabled = (Boolean) session.getAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_OPTIONS);
            if (optionsTracingEnabled == null) {
                optionsTracingEnabled = new Boolean(false);
            }

            Boolean tmlscriptOptimizationDisabled = (Boolean) session.getAttribute(WGACore.ATTRIB_TMLDEBUG_DISABLE_TMLSCRIPT_OPTIMIZATION);
            if (tmlscriptOptimizationDisabled == null) {
                tmlscriptOptimizationDisabled = new Boolean(false);
            }

            if (command == null) {
                request.getRequestDispatcher("/tmlDebugFrameset.jsp").include(request, response);
                return;
            }

            if (command.equalsIgnoreCase("toggledebug")) {
                debugModeEnabled = new Boolean(!debugModeEnabled.booleanValue());
                session.setAttribute(WGACore.ATTRIB_TMLDEBUG, debugModeEnabled);
                command = "status";
            }
            else if (command.equalsIgnoreCase("toggleresulttrace")) {
                resultTracingEnabled = new Boolean(!resultTracingEnabled.booleanValue());
                session.setAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_RESULTS, resultTracingEnabled);
                command = "status";
            }
            else if (command.equalsIgnoreCase("toggleoptionstrace")) {
                optionsTracingEnabled = new Boolean(!optionsTracingEnabled.booleanValue());
                session.setAttribute(WGACore.ATTRIB_TMLDEBUG_TRACE_OPTIONS, optionsTracingEnabled);
                command = "status";
            }
            else if (command.equalsIgnoreCase("toggletmlscriptoptimization")) {
                tmlscriptOptimizationDisabled = new Boolean(!tmlscriptOptimizationDisabled.booleanValue());
                session.setAttribute(WGACore.ATTRIB_TMLDEBUG_DISABLE_TMLSCRIPT_OPTIMIZATION, tmlscriptOptimizationDisabled);
                command = "status";
            }

            else if (command.equalsIgnoreCase("clearlist")) {
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                debugDocuments.clear();
                command = "list";
            }

            if (command.equalsIgnoreCase("toolbar")) {
                request.getRequestDispatcher("/tmlDebugToolbar.jsp").include(request, response);
            }
            else if (command.equalsIgnoreCase("status")) {
                response.getWriter().write("TMLScript stack traces are switched " + (tmlscriptOptimizationDisabled.booleanValue() ? "ON" : "OFF") + "\n");
                if (debugModeEnabled.booleanValue() == true) {
                    response.getWriter().write("WebTML debug mode is switched ON\n");
                    response.getWriter().write("Result tracing is switched " + (resultTracingEnabled.booleanValue() ? "ON" : "OFF") + "\n");
                    response.getWriter().write("Options tracing is switched " + (optionsTracingEnabled.booleanValue() ? "ON" : "OFF") + "\n");
                }
                else {
                    response.getWriter().write("WebTML debug mode is switched OFF\n");
                }

            }
            else if (command.equalsIgnoreCase("list")) {
                if (debugModeEnabled.booleanValue() == true) {
                    sendDebugDocList(request, response, session);
                }
                else {
                    throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "WebTML debug mode is not enabled. First enable it via tmldebug?command=on", null);
                }
            }
            else if (command.equalsIgnoreCase("showModules")) {
                showTMLModules(request, response, session);
            }
            else if (command.equalsIgnoreCase("showTags")) {
                showTMLTags(request, response, session);
            }
            else if (command.equalsIgnoreCase("show")) {
                sendDebugDoc(request, response, session);
            }
            else {
                throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "Unknown debug command: " + command, null);
            }

        }

        /**
         * @param request
         * @param response
         * @param session
         * @throws HttpErrorException
         * @throws IOException
         */
        private void sendDebugDoc(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws HttpErrorException, IOException {
            String urlStr = request.getParameter("url");
            String indexStr = request.getParameter("index");

            if (urlStr != null) {
                urlStr = URLDecoder.decode(urlStr, "UTF-8");
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                Document debugDoc;
                for (int idx = 0; idx < debugDocuments.size(); idx++) {
                    debugDoc = (Document) debugDocuments.get(idx);
                    if (debugDoc.getRootElement().attributeValue("url", "").equals(urlStr)) {
                        indexStr = String.valueOf(idx);
                        break;
                    }
                }
            }

            if (indexStr != null) {
                int index = Integer.valueOf(indexStr).intValue();
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                if (index == -1) {
                    index = debugDocuments.size() - 1;
                }
                if (index >= debugDocuments.size()) {
                    throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "Index out of range: " + index + " where maximum index is " + (debugDocuments.size() - 1), null);
                }
                else {
                    Document doc = (Document) debugDocuments.get(index);
                    response.setContentType("text/xml");
                    XMLWriter writer = new XMLWriter(response.getWriter());
                    writer.write(doc);
                }
            }
            else {
                throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "You must include either parameter index or url to address the debug document to show", null);
            }
        }

        /**
         * @param response
         * @param session
         * @throws IOException
         */
        private void sendDebugDocList(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {
            List debugDocuments = WGACore.getDebugDocumentsList(session);
            Document debugDoc;
            response.setContentType("text/html");
            Writer out = response.getWriter();
            out.write("<html><body>");
            out.write("<h2>Debug data for session " + session.getId());
            out.write("<table width='100%' border='1'>");
            out.write("<thead><th>index</th><th>url</th><th>started</th><th>ended</th></thead>");
            out.write("<tbody>");

            for (int idx = debugDocuments.size() - 1; idx > -1; idx--) {
                debugDoc = (Document) debugDocuments.get(idx);
                out.write("<tr>");
                out.write("<td>" + String.valueOf(idx) + "</td>");
                out.write("<td><a target=\"blank\" href=\"" + getContextPath() + "/tmlDebug?command=showModules&index=" + idx + "\">" + debugDoc.selectSingleNode("/tmldebugdocument/@url").getText()
                        + "</a></td>");
                out.write("<td>" + debugDoc.selectSingleNode("/tmldebugdocument/@started").getText() + "");
                out.write("<td>");
                Attribute endedElement = (Attribute) debugDoc.selectSingleNode("/tmldebugdocument/@ended");
                if (endedElement != null) {
                    out.write(endedElement.getText());
                }
                else {
                    out.write("&nbsp;");
                }
                out.write("</td></tr>");
            }

            out.write("</tbody></table>");
            out.write("<button onclick=\"location.href='" + request.getContextPath() + "/tmlDebug?command=clearlist'\">Clear list</button>");
            out.write("</body></html>");
        }

        private void showTMLModules(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws HttpErrorException, IOException {
            String urlStr = request.getParameter("url");
            String indexStr = request.getParameter("index");

            if (urlStr != null) {
                urlStr = URLDecoder.decode(urlStr, "UTF-8");
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                Document debugDoc;
                for (int idx = 0; idx < debugDocuments.size(); idx++) {
                    debugDoc = (Document) debugDocuments.get(idx);
                    if (debugDoc.getRootElement().attributeValue("url", "").equals(urlStr)) {
                        indexStr = String.valueOf(idx);
                        break;
                    }
                }
            }

            response.setContentType("text/html");

            if (indexStr != null) {
                int index = Integer.valueOf(indexStr).intValue();
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                if (index == -1) {
                    index = debugDocuments.size() - 1;
                }
                if (index >= debugDocuments.size()) {
                    throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "Index out of range: " + index + " where maximum index is " + (debugDocuments.size() - 1), null);
                }
                else {
                    Document doc = (Document) debugDocuments.get(index);
                    doc.getRootElement().addAttribute("index", String.valueOf(index));

                    try {
                        DOMWriter domWriter = new DOMWriter();
                        org.w3c.dom.Document domDocument = domWriter.write(doc);

                        Transformer trans = getDebugModulesTransformer(request.getParameter("throwAway") != null);
                        trans.transform(new DOMSource(domDocument), new StreamResult(response.getOutputStream()));
                    }
                    catch (TransformerConfigurationException e) {
                        response.sendError(500, e.getMessageAndLocation());
                        e.printStackTrace();
                    }
                    catch (TransformerFactoryConfigurationError e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                    catch (TransformerException e) {
                        response.sendError(500, e.getMessageAndLocation());
                        e.printStackTrace();
                    }
                    catch (IOException e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                    catch (DocumentException e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                }
            }
            else {
                throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "You must include either parameter index or url to address the debug document to show", null);
            }
        }

        private void showTMLTags(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws HttpErrorException, IOException {
            String urlStr = request.getParameter("url");
            String indexStr = request.getParameter("index");

            if (urlStr != null) {
                urlStr = URLDecoder.decode(urlStr, "UTF-8");
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                Document debugDoc;
                for (int idx = 0; idx < debugDocuments.size(); idx++) {
                    debugDoc = (Document) debugDocuments.get(idx);
                    if (debugDoc.getRootElement().attributeValue("url", "").equals(urlStr)) {
                        indexStr = String.valueOf(idx);
                        break;
                    }
                }
            }

            response.setContentType("text/html");

            if (indexStr != null) {
                int index = Integer.valueOf(indexStr).intValue();
                List debugDocuments = WGACore.getDebugDocumentsList(session);
                if (index == -1) {
                    index = debugDocuments.size() - 1;
                }
                if (index >= debugDocuments.size()) {
                    throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "Index out of range: " + index + " where maximum index is " + (debugDocuments.size() - 1), null);
                }
                else {
                    Document doc = (Document) debugDocuments.get(index);
                    Element element = (Element) doc.selectSingleNode(request.getParameter("root"));
                    doc = DocumentFactory.getInstance().createDocument(element.createCopy());
                    doc.getRootElement().addAttribute("index", String.valueOf(index));

                    try {
                        DOMWriter domWriter = new DOMWriter();
                        org.w3c.dom.Document domDocument = domWriter.write(doc);

                        Transformer trans = getDebugTagsTransformer(request.getParameter("throwAway") != null);
                        trans.transform(new DOMSource(domDocument), new StreamResult(response.getOutputStream()));
                    }
                    catch (TransformerConfigurationException e) {
                        response.sendError(500, e.getMessageAndLocation());
                        e.printStackTrace();
                    }
                    catch (TransformerFactoryConfigurationError e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                    catch (TransformerException e) {
                        response.sendError(500, e.getMessageAndLocation());
                        e.printStackTrace();
                    }
                    catch (IOException e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                    catch (DocumentException e) {
                        response.sendError(500, e.getMessage());
                        e.printStackTrace();
                    }
                }
            }
            else {
                throw new HttpErrorException(HttpServletResponse.SC_BAD_REQUEST, "You must include either parameter index or url to address the debug document to show", null);
            }
        }

    }

    public class TemporaryDownload implements HttpSessionBindingListener {

        private String _name;

        private TemporaryFile _tempFile;

        public TemporaryDownload(String name, TemporaryFile file) {
            super();
            this._name = name;
            this._tempFile = file;
        }

        public TemporaryFile getTempFile() {
            return _tempFile;
        }

        public String getName() {
            return _name;
        }

        protected void finalize() throws Throwable {
            _tempFile.delete();
        }

        public void valueBound(HttpSessionBindingEvent arg0) {
        }

        public void valueUnbound(HttpSessionBindingEvent arg0) {
            _tempFile.delete();
        }

    }

    public class RequestInformation {

        private Date _date;

        private boolean committed = false;

        public RequestInformation() {
            _date = new Date();
        }

        /**
         * @return Returns the date.
         */
        public Date getDate() {
            return _date;
        }

        /**
         * @param date
         *            The date to set.
         */
        public void setDate(Date date) {
            _date = date;
        }

        /**
         * @return Returns the committed.
         */
        public boolean isCommitted() {
            return committed;
        }

        /**
         * @param committed
         *            The committed to set.
         */
        public void setCommitted(boolean committed) {
            this.committed = committed;
        }
    }

    WGACore _core;

    private Logger _log;

    public static final String SESSION_VARS = "Vars";

    // Session attributes set by this program
    public static final String SESSION_LOGINS = "Logins";

    public static final String SESSION_PROFILENAME = "Profilename:";

    public static final String SESSION_PROFILENAME_INDIVIDUALDB = "ProfilenameDB:";

    // Session attribute where temporary downloads are registered
    public static final String SESSION_TEMPORARYDOWNLOADS = "TemporaryDownloads";

    // Other storage
    private boolean _servePages = false;

    private int _listenPort = -1;

    private String _contextPath = null;
   

    private WebTMLDebugger _tmlDebugger;
   
    protected WGAConfigurationOptionReader _variousServerOptionReader;

    public static final String DEFAULT_LANGUAGE_TOKEN = "int";

    // Config flags and infos

    public void doPut(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {
        this.doPost(request, response);
    }

    public void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {

        if (!isServePages()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Website is currently updating configuration. Please try again later.");
            return;
        }

        String path = request.getServletPath() + (request.getPathInfo() != null ? request.getPathInfo() : "");

        try {

            if (path.equals("/login")) {

                doLogin(request, response);
                return;

            }
            else if (path.equals("/logout")) {

                String domain = request.getParameter("domain");
                _core.logout(domain, request.getSession());
                sendRedirect(response, request.getParameter("redirect"));

            }
            else if (path.equals("/ajaxform")) {
                this.dispatchAjaxForm(request, response);
            }
            else {
                this.doGet(request, response);
            }

        }
        catch (Exception exc) {
            if (!(exc instanceof HttpErrorException)) {
                _log.error("Error in request processing", exc);
            }
            request.setAttribute(WGACore.ATTRIB_EXCEPTION, exc);
            throw new ServletException(exc);
        }
        catch (Error err) {
            _log.error("Error in request processing", err);
            request.setAttribute(WGACore.ATTRIB_EXCEPTION, err);
            throw new ServletException(err);
        }
    }

    /**
     * retrieve posted formdata, parse request, store posted data in
     * temp-sessionkey, render javascript-callbackfunction to submit sessionkey
     * to clientside ajax call
     *
     * @param request
     * @param response
     */
    private void dispatchAjaxForm(HttpServletRequest request, HttpServletResponse response) {
        // skip logging
        WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
        if (info != null) {
            info.setType(WGARequestInformation.TYPE_AJAXFORM);
        }

        if (FileUpload.isMultipartContent(request)) {
            DiskFileUpload dfu = new DiskFileUpload();
            // F000037B2
            if (getCore().getCharacterEncoding() != null) {
                dfu.setHeaderEncoding(getCore().getCharacterEncoding());
            }
            try {
                // parse request
                List fileItems = dfu.parseRequest(request);
                Iterator iter = fileItems.iterator();

                String formaction = null;
                String ajaxcallid = null;
                String ajaxgraydiv = null;
                String ajaxmode = null;
                while (iter.hasNext()) {
                    FileItem fi = (FileItem) iter.next();
                    if (fi.isFormField()) {
                        String fieldValue = null;
                        if (_core.getCharacterEncoding() != null) {
                            fieldValue = fi.getString(_core.getCharacterEncoding());
                        }
                        else {
                            fieldValue = fi.getString();
                        }
                        if (fi.getFieldName().equals("$formaction")) {
                            formaction = fieldValue;
                        }
                        else if (fi.getFieldName().equals("$ajaxcallid")) {
                            ajaxcallid = fieldValue;
                        }
                        else if (fi.getFieldName().equals("$ajaxgraydiv")) {
                            ajaxgraydiv = fieldValue;
                        }
                        else if (fi.getFieldName().equals("$ajaxmode")) {
                            ajaxmode = fieldValue;
                        }
                    }
                }
                if (formaction == null || ajaxcallid == null) {
                    getCore().getLog().error("Could not retrieve 'formaction' or 'ajaxcallid' from ajaxform-data.");
                    return;
                }
                else {
                    // generate temp session key
                    String sessionKey = UIDGenerator.generateUID();
                    TransientList transientList = new TransientList(fileItems);

                    // store posted data transient on session - bc. fileItems
                    // are not serializable
                    request.getSession().setAttribute(sessionKey, transientList);
                    // check if session is new
                    if (request.getSession().isNew()) {
                        // server create new session in an ajax form call
                        // set flag on session and later render
                        // Event.SESSION_IS_NEW_EVENT
                        // in ajax call to notify client
                        // the sessionflag is handled and removed in root-tag
                        request.getSession().setAttribute(sessionKey + ".event.SessionWasNew", new Boolean(true));
                    }

                    // create action definition
                    AjaxActionDefinition actionDef = new AjaxActionDefinition(formaction, ajaxcallid);
                    actionDef.setTmlformSessionKey(sessionKey);
                    if (ajaxgraydiv != null && !ajaxgraydiv.equals("#null#")) {
                        actionDef.setGraydiv(Boolean.valueOf(ajaxgraydiv).booleanValue());
                    }
                    if (ajaxmode != null && !ajaxmode.equals("#null#")) {
                        actionDef.setMode(ajaxmode);
                    }

                    // render response
                    response.setContentType("text/html");
                    PrintWriter out = response.getWriter();
                    out.write("<script type=\"text/javascript\">");
                    out.write("parent.WGA.ajax.formCallback(" + actionDef.toJavaScriptObject() + ");");
                    out.write("</script>");
                }
            }
            catch (FileUploadException e) {
                getCore().getLog().error("Error parsing multipart-data from ajaxcall: " + e.getMessage());
            }
            catch (IOException e) {
                getCore().getLog().error("Error creating ajaxcall response.", e);
            }
        }

    }

    private void doLogin(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws HttpErrorException, IOException, MalformedURLException,
            ServletException, WGAPIException {

        // Get the necessary fields
        String domain = request.getParameter("domain");
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String redirect = request.getParameter("redirect");
        String referer = request.getHeader("Referer");

        // Some basic validating
        if (domain == null) {
            throw new HttpErrorException(500, "Missing parameter \"domain\". (Hint: Field name must be lower case)", null);
        }
        if (username == null) {
            throw new HttpErrorException(500, "Missing parameter \"username\". (Hint: Field name must be lower case)", null);
        }
        if (password == null) {
            throw new HttpErrorException(500, "Missing parameter \"password\". (Hint: Field name must be lower case)", null);
        }
        if (username == null || password == null) {
            request.setAttribute(WGACore.ATTRIB_LOGINERROR, "Invalid login for domain " + domain + ". Username or password is null.");
            username = "Anonymous";
            password = "";
        }

        boolean isLoginSuccessful = false;
        try {
            if (WGACore.DOMAIN_ADMINLOGINS.equals(domain)) {
                if (!_core.isAdministrativePort(request.getLocalPort())) {
                    throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "Access to administrative applications is disabled", null);
                }

                isLoginSuccessful = _core.doAdminLogin(username, password, request);
            }
            else {
                isLoginSuccessful = _core.login(username, password, domain, request, response);
            }
        }
        catch (LoginException e) {
            throw new ServletException("Login Error", e);
        }

        // React on login success
        if (isLoginSuccessful) {

            if (redirect != null) {
                sendRedirect(response, redirect);
            }
            else if (referer != null) {
                request.setAttribute(WGACore.ATTRIB_LOGINERROR, "No redirect specified.");
                de.innovationgate.utils.URLBuilder builder = new de.innovationgate.utils.URLBuilder(new java.net.URL(referer));
                builder.setParameter("loginerror", "1");
                sendRedirect(response, builder.rebuild(false));
            }
            else {
                response.setStatus(HttpServletResponse.SC_OK);
            }
        }
        else {

            if (WGACore.DOMAIN_ADMINLOGINS.equals(domain)) {
                request.setAttribute(WGACore.ATTRIB_LOGINERROR, "Invalid administrative login. Please verify username and password.");
            }
            else {
                request.setAttribute(WGACore.ATTRIB_LOGINERROR, "Invalid login for domain " + domain + ". Please verify username and password.");
            }

            if (request.getParameter("flag") != null) {
                response.setContentType("text/html");
                request.getRequestDispatcher("login.jsp").include(request, response);
            }
            else if (referer != null) {
                de.innovationgate.utils.URLBuilder builder = new de.innovationgate.utils.URLBuilder(new java.net.URL(referer));
                builder.setParameter("loginerror", "1");
                sendRedirect(response, builder.rebuild(false).toString());
            }
            else {
                response.sendError(HttpServletResponse.SC_FORBIDDEN, "Invalid login");
            }
        }
        return;
    }

    public void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, java.io.IOException {

        if (!isServePages()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "Website is currently updating configuration. Please try again later.");
            return;
        }

        Date startDate = new Date();

        if (this._contextPath == null) {
            this._contextPath = request.getContextPath();
            this._listenPort = request.getServerPort();
        }

        try {

            // Retrieve session
            javax.servlet.http.HttpSession session = request.getSession();
            if (session.isNew()) {
                session.setAttribute(SESSION_VARS, new HashMap());
            }

            // Parse request
            WGPRequestPath path = parseRequest(request, response);
            request.setAttribute(WGACore.ATTRIB_REQUESTPATH, path);

            // If database login failed exit immediately
            if (!path.isProceedRequest()) {
                return;
            }

            // Set access logging for this request
            if (path.getDatabase() != null) {
                String accessLoggingEnabled = (String) path.getDatabase().getAttribute(WGACore.DBATTRIB_ENABLE_ACCESSLOGGING);
                if (accessLoggingEnabled != null) {
                    WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
                    if (info != null) {
                        info.setLoggingEnabled(Boolean.parseBoolean(accessLoggingEnabled));
                    }
                }
            }

            int iPathType = path.getPathType();

            // Treatment of special URL types
            String dbKey = path.getDatabaseKey();
            if (iPathType == WGPRequestPath.TYPE_INVALID) {
                throw new HttpErrorException(404, "Invalid path: " + path.getBasePath(), dbKey);
            }
            if (iPathType == WGPRequestPath.TYPE_INVALID_DB) {
                throw new HttpErrorException(404, "Specified database '" + dbKey + "' is unknown", null);
            }

            if (iPathType == WGPRequestPath.TYPE_UNKNOWN_CONTENT) {
                sendNoContentNotification(path, request, response, path.getDatabase());
                return;
            }

            if (iPathType == WGPRequestPath.TYPE_GOTO_HOMEPAGE) {
                iPathType = determineHomepage(request, path, iPathType);
            }

            if (iPathType == WGPRequestPath.TYPE_UNAVAILABLE_DB) {
                throw new HttpErrorException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "The website is currently unavailable", path.getDatabaseKey());
            }

            if (iPathType == WGPRequestPath.TYPE_UNDEFINED_HOMEPAGE) {
                throw new HttpErrorException(HttpServletResponse.SC_NOT_FOUND, "No home page was defined for database '" + path.getDatabaseKey() + "'. Please specify an explicit content path.", path
                        .getDatabaseKey());
            }

            if (iPathType == WGPRequestPath.TYPE_TMLDEBUG) {
                _tmlDebugger.performDebugMode(request, response, session);
                return;
            }

            if (iPathType == WGPRequestPath.TYPE_JOBLOG) {
                sendJobLog(request, response, session);
                return;
            }

            if (iPathType == WGPRequestPath.TYPE_LOGOUT) {
                WGDatabase db = (WGDatabase) _core.getContentdbs().get(dbKey);
                String domain = (String) db.getAttribute(WGACore.DBATTRIB_DOMAIN);
                _core.logout(domain, session);
                removeSessionCookie(response, request.getSession(), db);

                iPathType = WGPRequestPath.TYPE_REDIRECT;
            }

            if (iPathType == WGPRequestPath.TYPE_FAVICON) {
                String faviconPath = determineFavicon(request);
                if (faviconPath != null) {
                    iPathType = WGPRequestPath.TYPE_REDIRECT;
                    path.setResourcePath(faviconPath);
                }
                else {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND, "Favicon not defined");
                    return;
                }
            }

            // Treatment of base URL Types
            if (iPathType == WGPRequestPath.TYPE_REDIRECT) {
                String url = path.getResourcePath();
                if (path.appendQueryString() == true && request.getQueryString() != null && !request.getQueryString().equals("")) {
                    if (url.indexOf("?") != -1) {
                        url += "&" + request.getQueryString();
                    }
                    else {
                        url += "?" + request.getQueryString();
                    }
                }

                if (path.isPermanentRedirect()) {
                    sendPermanentRedirect(response, url);
                }
                else {
                    sendRedirect(response, url);
                }
            }
            else if (iPathType != WGPRequestPath.TYPE_RESOURCE && iPathType != WGPRequestPath.TYPE_STATICTML && !_core.getContentdbs().containsKey(path.getDatabaseKey())) {
                throw new HttpErrorException(404, "Database '" + dbKey + "' is unknown", null);
            }
            else {

                String requestMethod = request.getMethod().toLowerCase();
                switch (iPathType) {
                    case (WGPRequestPath.TYPE_TML):
                    case (WGPRequestPath.TYPE_TITLE_PATH):
                        if (path.isCompletePath() || !(requestMethod.equals("get") || requestMethod.equals("head"))) {

                            if (!path.isCompletePath()) {
                                _log.warn("Received " + request.getMethod() + " request to incomplete URL '" + path.getCompleteURL()
                                        + "' which cannot be redirected. Please use complete URLs on this HTTP method for consistent behaviour.");
                            }

                            dispatchTmlRequest(path, request, response, startDate);
                        }
                        else {
                            sendRedirect(response, path.expandToCompletePath(request));
                        }
                        break;

                    case (WGPRequestPath.TYPE_FILE):
                        dispatchFileRequest(path, request, response);
                        break;

                    case (WGPRequestPath.TYPE_CSS):
                    case (WGPRequestPath.TYPE_JS):
                        dispatchCssjsRequest(path, request, response);
                        break;

                    case (WGPRequestPath.TYPE_RESOURCE):
                        dispatchResourceRequest(path, request, response);
                        break;

                    case (WGPRequestPath.TYPE_STATICTML):
                        dispatchStaticTmlRequest(path, request, response);
                        break;

                    default:
                        throw new HttpErrorException(500, "Invalid url format", dbKey);
                }
            }

            // moved from finally block to ensure errorpage can be displayed
            commitResponse(response);
        }
        catch (HttpErrorException exc) {
            request.setAttribute(WGACore.ATTRIB_EXCEPTION, exc);
            if (!response.isCommitted()) {
                // throw exception to display errorpage - with senderror() the
                // applicationserver use the buildin errorpage
                if (exc.getCode() == HttpServletResponse.SC_NOT_FOUND || exc.getCode() == HttpServletResponse.SC_FORBIDDEN) {
                    _log.warn(exc.getLogMessage(request));
                    response.sendError(exc.getCode(), exc.getMessage());
                }
                else {
                    throw new ServletException(exc);
                }
            }
            else {
                _log.warn(exc.getLogMessage(request));
            }
        }
        catch (SocketException exc) {
            _log.warn("Socket Exception: " + exc.getMessage());
        }
        catch (Exception exc) {
            _log.error("Exception in processing of request URL " + String.valueOf(request.getRequestURL()), exc);
            request.setAttribute(WGACore.ATTRIB_EXCEPTION, exc);
            throw new ServletException(exc);
        }
        catch (Error err) {
            _log.error("Error in processing of request URL " + String.valueOf(request.getRequestURL()), err);
            request.setAttribute(WGACore.ATTRIB_EXCEPTION, err);
            throw new ServletException(err);
        }
        finally {
            WGARequestInformation reqInfo = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
            if (reqInfo != null) {
                reqInfo.setCommited(true);
            }
        }
    }
   
    private void sendPermanentRedirect(HttpServletResponse response, String url) {
        response.setStatus(301);
        response.setHeader( "Location", url);
        response.setHeader( "Connection", "close");
    }

    private WGPRequestPath parseRequest(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws HttpErrorException, WGException, IOException {
        return new WGPRequestPath(request, response, this, _core);
    }

    private int determineHomepage(javax.servlet.http.HttpServletRequest request, WGPRequestPath path, int iPathType) throws UnsupportedEncodingException, HttpErrorException {
        WGDatabase db = (WGDatabase) _core.getContentdbs().get(path.getDatabaseKey());

        WGAURLBuilder urlBuilder = _core.retrieveURLBuilder(request, db);

        String homepage;
        try {
            homepage = urlBuilder.buildHomepageURL(db, request);
            if (homepage != null) {
                path.setResourcePath(homepage);
                return WGPRequestPath.TYPE_REDIRECT;
            }
        }
        catch (WGException e) {
            getCore().getLog().error("Error determining homepage", e);
            throw new HttpErrorException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage(), path.getDatabaseKey());
        }

        return WGPRequestPath.TYPE_UNDEFINED_HOMEPAGE;
    }

    public String determineFavicon(HttpServletRequest request) {

        String faviconPath = getCore().getWgaConfiguration().getFavicon();
        if (faviconPath != null) {
            if (faviconPath.indexOf("://") == -1 && !faviconPath.startsWith("/")) {
                faviconPath = "/" + faviconPath;
            }
            return faviconPath;
        }
        else {
            return null;
        }

    }

    private void commitResponse(javax.servlet.http.HttpServletResponse response) {
        if (!response.isCommitted()) {
            try {
                response.flushBuffer();
            }
            catch (IOException e) {
            }
        }
    }

    /**
     * @param request
     * @param response
     * @param session
     */
    private void sendJobLog(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException {

        if (!isAdminLoggedIn(request)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "You must be logged in as WGA administrator!");
            return;
        }

        String jobToShow = request.getParameter("name");
        Job job = getCore().getScheduler().getJob(jobToShow);
        if (job == null) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Unknown job: " + jobToShow);
            return;
        }

        response.setContentType("text/html");
        Writer out = response.getWriter();
        out.write("<HTML><HEAD>");

        out.write("\n<script language=\"javascript\">\nvar running=" + Boolean.valueOf(job.isRunning()).toString() + ";\n</script>\n");

        /*
         * if (job.isRunning()) {
         * out.write("<META HTTP-EQUIV=\"refresh\" CONTENT=\"3\"/>"); } else {
         * out.write("<META HTTP-EQUIV=\"refresh\" CONTENT=\"6\"/>"); }
         */
        out.write("</HEAD>");
        out.write("<BODY style=\"background-color:white; font-family:sans-serif; font-size:10pt\">");
        String log = job.getLog();
        LineNumberReader reader = new LineNumberReader(new StringReader(log));
        String line;
        while ((line = reader.readLine()) != null) {
            out.write(line);
            out.write("<BR/>");
        }

        if (!job.isRunning() && job.getEndMessage() != null) {
            out.write("<p>");
            out.write("<table border=\"1\" cellpadding=\"5\"><tr><td>");
            out.write(job.getEndMessage());
            out.write("</td></tr></table>");
            out.write("</p>");
        }
        out.write("<a id=\"bottomLink\" name=\"bottom\">&nbsp;</a></BODY></HTML>");

    }

    private void dispatchTmlRequest(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Date startDate) throws java.lang.Exception {

        boolean ajax = false;

        String completeUrl = path.getCompleteURL();

        HttpSession session = request.getSession();

        // Fetch the database
        WGDatabase database = path.getDatabase();
        if (database == null) {
            throw new HttpErrorException(404, "No database of key " + path.getDatabaseKey(), null);
        }

        // Determine requested mime type and type key
        String mediaKey = path.getMediaKey();
        if (mediaKey == null) {
            mediaKey = database.getAttribute(WGACore.DBATTRIB_DEFAULT_MEDIAKEY).toString();
        }
        MediaKey mediaKeyObj = _core.getMediaKey(mediaKey);
        String mimeType = mediaKeyObj.getMimeType();
        response.setContentType(mimeType);

        // Look if a session cookie has to be set
        _core.setSessionCookie(request, response, database);

        // Determine the content for this request
        WGContent content = path.getContent();

        // Context request, if content key filled or we have a title path
        if (content != null) {

            if (!content.mayBePublished(isBrowserInterface(session) || isAuthoringMode(database.getDbReference(), session), WGContent.DISPLAYTYPE_NONE)) {
                sendNoContentNotification(path, request, response, database);
                return;
            }

            if (content.isVirtual()) {
                if (isBrowserInterface(session)) {
                    if (!content.getStatus().equals(WGContent.STATUS_DRAFT) && request.getParameter("forceVLink") == null) {

                        String url = getVirtualContentURL(request, database, path, content);
                        sendRedirect(response, url);
                        return;
                    }
                }
                else {
                    sendRedirect(response, buildVirtualLink(content, request, path.getMediaKey(), path.getLayoutKey()));
                    return;
                }
            }

        }

        // Contextless request. We use a dummy content
        else {
            content = database.getDummyContent(path.getRequestLanguage());
        }

        // Test browsability of content
        if (!content.isDummy() && getBrowsingSecurity(database) <= BrowsingSecurity.NO_BROWSING) {
            throw new HttpErrorException(java.net.HttpURLConnection.HTTP_FORBIDDEN, "Browsing not allowed in database '" + path.getDatabaseKey() + "'", path.getDatabaseKey());
        }

        // Drop cache if requested by url param
        if (request.getQueryString() != null && request.getQueryString().toLowerCase().indexOf("dropcache") != -1 && isAdminLoggedIn(request)) {
            content.dropCache();
        }

        // Personalize
        TMLUserProfile tmlUserProfile = null;
        try {
            if (_core.isPersonalisationEnabled()) {
                tmlUserProfile = this.fetchUserProfile(request, response, database, session);
                if (tmlUserProfile != null && !tmlUserProfile.getprofile().isDeleted()) {
                    if (!isBrowserInterface(session)) {
                        this.registerHit(tmlUserProfile.getprofile(), database, content);
                    }
                }
            }
        }
        catch (WGAPIException e) {
            _log.error("Unable to personalize tmlrequest.", e);
        }

        // Set context attributes for tml
        request.setAttribute(WGACore.ATTRIB_MAINCONTEXT, content);
        request.setAttribute(WGACore.ATTRIB_WGPPATH, path.getPublisherURL());
        request.setAttribute(WGACore.ATTRIB_TAGIDS, WGUtils.createSynchronizedMap());
        request.setAttribute(WGACore.ATTRIB_TMLCONTEXTS, WGUtils.createSynchronizedMap());
        request.setAttribute(WGACore.ATTRIB_REQUESTURL, completeUrl);
        request.setAttribute(WGACore.ATTRIB_MIMETYPE, mimeType);
        request.setAttribute(WGACore.ATTRIB_MEDIAKEY, mediaKey);
        request.setAttribute(WGACore.ATTRIB_REQUESTTYPE, REQUESTTYPE_TML);

        if (mediaKeyObj.isBinary()) {
            request.setAttribute(WGACore.ATTRIB_SERVLETRESPONSE, response);
        }

        // Determine tml design for this request
        WGTMLModule tmlLib = null;
        if (path.getLayoutKey() != null) {
            tmlLib = (WGTMLModule) database.getDesignObject(WGDocument.TYPE_TML, path.getLayoutKey(), mediaKey);
            if (tmlLib != null && tmlLib.isDirectAccessAllowed() == false) {
                throw new HttpErrorException(java.net.HttpURLConnection.HTTP_FORBIDDEN, "This design is not allowed for direct access: " + tmlLib.getName() + " (" + tmlLib.getMediaKey() + ")", path
                        .getDatabaseKey());
            }
        }
        else {
            WGStructEntry entry = content.getStructEntry();
            if (entry == null) {
                throw new HttpErrorException(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Content " + content.getContentKey().toString() + " has no struct entry", path.getDatabaseKey());
            }
            tmlLib = entry.getOuterLayout(mediaKey);
        }

        if (tmlLib == null || tmlLib.isDummy()) {
            if (path.getLayoutKey() != null) {
                throw new HttpErrorException(404, "No WebTML layout '" + path.getLayoutKey() + "' for media key '" + mediaKey + "' available in app '" + database.getDbReference() + "'", path.getDatabaseKey());
            }
            else {
                throw new HttpErrorException(500, "Outer layout of struct entry '" + content.getStructEntry().getTitle() + "(" + content.getStructEntry().getStructKey() + ")"
                        + "' not available for media key '" + mediaKey + "'", path.getDatabaseKey());
            }
        }

        request.setAttribute(WGACore.ATTRIB_OUTER_DESIGN, tmlLib.getName());


        // TML Cache control
        if (tmlLib.isCacheable()) {
            response.setHeader("Cache-Control", "must-revalidate");

            long lastModified;
            // determine lastModified
            // - last modified of binary response depends only on resource
            // change date
            // - last change date of textual response additionally depends on
            // character encoding change date
            if (isBinary(response)) {
                lastModified = getCore().getDeployer().getLastChangedOrDeployed(database).getTime();
            }
            else {
                lastModified = Math.max(getCore().getDeployer().getLastChangedOrDeployed(database).getTime(), _core.getCharacterEncodingLastModified());
                lastModified = Math.max(lastModified, _core.getDesignEncodingLastModified(database.getDbReference()));
            }

            // Test modified since
            if (browserCacheIsValid(request, lastModified)) {
                response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                return;
            }
            else {
                response.setDateHeader("Last-Modified", lastModified);
                response.setHeader("ETag", '"' + String.valueOf(lastModified) + '"');
            }
        }
        else {
            response.setHeader("Pragma", "No-Cache");
            if (mediaKeyObj.isBinary()) {
                response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
            }
            else {
                response.setHeader("Cache-Control", "No-Cache");
            }
        }

        // check if we have an ajaxcall
        String encAjaxInfo = request.getParameter("$ajaxInfo");
        if (encAjaxInfo != null) {
            tmlLib = processAjaxCall(request, database, encAjaxInfo);
            ajax = true;
        }

        // Update usage statistics
        getCore().getUsageStatistics().addRequestStatistic(request, session, database, tmlUserProfile);

        // Dispatch to jsp
        String targetJSP = _core.getDeployer().locateTmlResource(tmlLib);

        try {
            if (targetJSP != null) {
                if (!"HEAD".equalsIgnoreCase(request.getMethod())) {
                    if (mediaKeyObj.isBinary()) {
                        if (request instanceof RenderServletRequestWrapper) {
                            HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request;
                            wrapper.getRequest().getRequestDispatcher(targetJSP).include(wrapper.getRequest(), new DummyServletResponse(response));
                        }
                        else {
                            this.getServletContext().getRequestDispatcher(targetJSP).include(request, new DummyServletResponse(response));
                        }
                    }
                    else {
                        if (request instanceof RenderServletRequestWrapper) {
                            HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request;
                            wrapper.getRequest().getRequestDispatcher(targetJSP).include(wrapper.getRequest(), response);
                        }
                        else {
                            this.getServletContext().getRequestDispatcher(targetJSP).include(request, response);
                        }
                    }
                }
            }
            else {
                throw new HttpErrorException(500, "tml design not active: " + tmlLib.getName(), path.getDatabaseKey());
            }

            // Eventually do redirect
            if (request.getAttribute(WGACore.ATTRIB_REDIRECT) != null) {
               
                if (!ajax) { // On AJAX requests the redirect is performed by Root.tmlEndTag()
                    if (!session.isNew()) { // on new sessions we must not reset the response (#00000147)
                        response.reset();
                    }
                    response.sendRedirect(String.valueOf(request.getAttribute(WGACore.ATTRIB_REDIRECT)));
                }
            }

            // Eventually save profile
            if (tmlUserProfile != null && tmlUserProfile.isSavedOnEnd() && !tmlUserProfile.isSaved()) {

                // To keep profile storage operation from delaying the response
                commitResponse(response);

                if (!tmlUserProfile.getprofile().save()) {
                    getCore().getLog().error("Unable to save profile on request end");
                }

            }
        }
        catch (Exception t) {
            throw t;
        }
        finally {
            // Log
            // WGALoggerWrapper logger = (WGALoggerWrapper)
            // database.getAttribute(WGACore.DBATTRIB_LOGGER);
            // if (logger != null) {
            // logger.logRequest(mimeType, path, request, content,
            // tmlUserProfile, tmlLib);
            // }
            WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
            if (info != null) {
                if (content == null || content.isDummy()) {
                    info.setType(WGARequestInformation.TYPE_TML);
                }
                else {
                    info.setType(WGARequestInformation.TYPE_CONTENT);
                }
                info.setDatabase(database);
                info.setMimeType(mimeType);
                info.setPath(path);
                info.setContent(content);
                info.setProfile(tmlUserProfile);
                info.setDesign(tmlLib);
                info.setAjax(ajax);
            }
        }
    }

    public static boolean isAuthoringMode(String dbReference, HttpSession session) {

        if (session == null) {
            return false;
        }

        String attName = WGACore.ATTRIB_AUTHORINGMODE + dbReference;
        Boolean bi = (Boolean) session.getAttribute(attName);
        if (bi != null && bi.booleanValue() == true) {
            return true;
        }
        else {
            return false;
        }

    }

    private WGTMLModule processAjaxCall(javax.servlet.http.HttpServletRequest request, WGDatabase database, String encAjaxInfo) throws HttpErrorException, WGException {
        WGTMLModule tmlLib;
        AjaxInfo ajaxInfo = null;
        try {
            // decrypt
            byte[] zipped = this.getCore().getDesEncrypter().decrypt(encAjaxInfo);
            if (zipped == null) {
                this.getCore().getLog().error("Retrieved AjaxInfo could not be decrypted. Maybe the ajax call was defined for another WGA instance.");
                throw new HttpErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "Retrieved AjaxInfo could not be decrypted. Maybe the ajax call was defined for another WGA instance.", null);
            }
            // unzip
            String unzipped = Zipper.unzip(zipped);
            // deserialize
            ajaxInfo = (AjaxInfo) new XStream(new Dom4JDriver()).fromXML(unzipped);
            // put ajaxInfo on request so root tag can retrieve it
            request.setAttribute(WGACore.ATTRIB_AJAXINFO, ajaxInfo);
        }
        catch (HttpErrorException e) {
            throw e;
        }
        catch (Exception e) {
            this.getCore().getLog().error("Retrieved AjaxInfo could not be restored.", e);
            throw new HttpErrorException(HttpURLConnection.HTTP_INTERNAL_ERROR, "Retrieved AjaxInfo could not be restored. Check log for details.", null);
        }

        // fetch correct db for ajax (if designdb on include tag is present use
        // design db, if not use current db)
        WGDatabase ajaxDB = null;
        String ajaxDesignDBKey = ajaxInfo.getDesignDB();
        if (ajaxDesignDBKey != null) {
            // fetch design db
            try {
                ajaxDB = _core.openContentDB(ajaxDesignDBKey, request);
            }
            catch (WGUnavailableException e) {
                throw new HttpErrorException(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "The website is currently unavailable", ajaxDesignDBKey);
            }
            catch (de.innovationgate.wgpublisher.AuthenticationException e) {
                throw new HttpErrorException(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage(), null);
            }
            catch (AccessException e) {
                throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, e.getMessage(), null);
            }

            if (ajaxDB == null) {
                throw new HttpErrorException(HttpServletResponse.SC_NOT_FOUND, "No database of key " + ajaxDesignDBKey, null);
            }
            else if (ajaxDB.isSessionOpen() == false) {
                throw new HttpErrorException(HttpServletResponse.SC_FORBIDDEN, "Database '" + ajaxDesignDBKey + "' could not be opened by ajaxCall.", null);
            }
        }
        else {
            ajaxDB = database;
        }

        // search for tml module
        tmlLib = (WGTMLModule) ajaxDB.getDesignObject(WGDocument.TYPE_TML, ajaxInfo.getTmlmodule(), ajaxInfo.getMediaKey());

        if (tmlLib == null) {
            throw new HttpErrorException(HttpServletResponse.SC_NOT_FOUND, "No WebTML layout '" + ajaxInfo.getTmlmodule() + "' for media key '" + ajaxInfo.getMediaKey() + "' available in app '" + ajaxDB.getDbReference() + "'", ajaxDB
                    .getDbReference());
        }

        return tmlLib;
    }

    private void sendNoContentNotification(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, WGDatabase database)
            throws IOException, HttpErrorException {
        if (request.getQueryString() != null && request.getQueryString().toLowerCase().indexOf("login") != -1) {
            sendRedirect(response, getLoginURL(request, database, path.getCompleteURL()));
        }
        else {

            if (isBrowserInterface(request.getSession()) && (path.getPathType() == WGPRequestPath.TYPE_TML || path.getPathType() == WGPRequestPath.TYPE_UNKNOWN_CONTENT)) {
                String url = getNoContentNotificationURL(request, database, path);
                sendRedirect(response, url);
            }
            else {
                if (path.getTitlePathURL() != null) {
                    throw new HttpErrorException(404, "Content on path '" + path.getTitlePathURL().getPath() + "' does not exist or is not visible for user '"
                            + database.getSessionContext().getUser() + "'", path.getDatabaseKey());
                }
                else {
                    throw new HttpErrorException(404, "Content of name/id '" + path.getContentKey() + "' does not exist or is not visible for user '" + database.getSessionContext().getUser() + "'",
                            path.getDatabaseKey());
                }
            }

        }
    }

    private void sendNoFileContainerNotification(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, WGDatabase database)
            throws IOException, HttpErrorException {

        if (request.getQueryString() != null && request.getQueryString().toLowerCase().indexOf("login") != -1) {
            sendRedirect(response, getLoginURL(request, database, path.getCompleteURL()));
        }
        else {
            throw new HttpErrorException(404, "No file container of name " + path.getContainerKey(), path.getDatabaseKey());
        }

    }

    private void removeSessionCookie(javax.servlet.http.HttpServletResponse response, HttpSession session, WGDatabase database) {
        if (!database.hasFeature(WGDatabase.FEATURE_SESSIONTOKEN)) {
            return;
        }

        String cookieName = (String) database.getAttribute(WGACore.DBATTRIB_SESSIONCOOKIE);
        if (cookieName == null) {
            return;
        }

        Cookie sessionCookie = new Cookie(cookieName, "");
        sessionCookie.setMaxAge(0);
        sessionCookie.setPath("/");
        String sessionCookieDomain = (String) database.getAttribute(WGACore.DBATTRIB_SESSIONCOOKIEDOMAIN);
        if (sessionCookieDomain != null) {
            sessionCookie.setDomain(sessionCookieDomain);
        }
        response.addCookie(sessionCookie);
        session.removeAttribute(WGACore.SESSION_COOKIESET + cookieName);

    }

    protected void sendRedirect(javax.servlet.http.HttpServletResponse response, String virtualLink) throws IOException {
        // send redirect always via j2ee method
        // B00004862
        response.sendRedirect(response.encodeRedirectURL(virtualLink));
    }

    /**
     * Method isBrowserInterface.
     *
     * @param request
     * @return boolean
     */
    public static boolean isBrowserInterface(HttpSession session) {

        if (session == null) {
            return false;
        }

        Boolean bi = (Boolean) session.getAttribute(WGACore.ATTRIB_BROWSERINTERFACE);
        if (bi != null && bi.booleanValue() == true) {
            return true;
        }
        else {
            return false;
        }
    }

    public static String buildContentURLID(WGContent content, String mediaKey, boolean isBI) throws WGAPIException {

        String language = content.getLanguage().getName();
        if (!LanguageBehaviourTools.isMultiLanguageDB(content.getDatabase()) && language.equals(content.getDatabase().getDefaultLanguage())) {
            language = DEFAULT_LANGUAGE_TOKEN;
        }

        StringBuffer idBuffer = new StringBuffer();
        String uniqueName = content.getStructEntry().getUniqueName();
        if (WGUtils.isEmpty(uniqueName)) {
            uniqueName = content.getUniqueName();
        }

        if (!WGUtils.isEmpty(uniqueName) && !isBI && content.getStatus().equals(WGContent.STATUS_RELEASE) && content.getDatabase().getBooleanAttribute(WGACore.DBATTRIB_CREATE_NAME_URLS, true)) {
            idBuffer.append(uniqueName).append(".");
            idBuffer.append(language).append(".");
            idBuffer.append(mediaKey);
        }
        else {
            idBuffer.append(String.valueOf(content.getStructKey())).append(".");
            idBuffer.append(language).append(".");
            if (content.getStatus().equals(WGContent.STATUS_RELEASE)) {
                idBuffer.append(mediaKey);
            }
            else {
                idBuffer.append(content.getVersion());
            }
        }
        return idBuffer.toString();
    }

    public static String buildLayoutURLID(WGDatabase db, String layoutKey, String language, String mediaKey) throws WGAPIException {

        if (db != null && !LanguageBehaviourTools.isMultiLanguageDB(db) && language.equals(db.getDefaultLanguage())) {
            language = DEFAULT_LANGUAGE_TOKEN;
        }

        StringBuffer idBuffer = new StringBuffer();
        idBuffer.append(layoutKey).append(".");
        idBuffer.append(language).append(".");
        idBuffer.append(mediaKey);
        return idBuffer.toString();

    }

    /**
     * retrieves a relative url from session attribute
     * WGACore.ATTRIB_NO_CONTENT_NOTIFCATION_URL to use as
     * NoContentNotificationURL in sendNoContentNotification(...) default is
     * "/statictml/#DBKEY#/dispNoContent?key=#KEY#" parameters #DBKEY# and
     * #TKEY# are replaced by the corresponding values,
     *
     * @param request
     * @param database
     * @param path
     * @return URL starting with getContextPath();
     */
    private String getNoContentNotificationURL(HttpServletRequest request, WGDatabase database, WGPRequestPath path) {
        // default URL used by old BI
        String defaultURL = "/statictml/#DBKEY#/dispNoContent?key=#KEY#";

        String relativeURL = null;
        if (request.getSession().getAttribute(WGACore.ATTRIB_NO_CONTENT_NOTIFCATION_URL) != null) {
            relativeURL = (String) request.getSession().getAttribute(WGACore.ATTRIB_NO_CONTENT_NOTIFCATION_URL);
        }
        else {
            relativeURL = defaultURL;
        }

        // replace variables in relative URL
        relativeURL = relativeURL.replaceAll("#DBKEY#", database.getAttribute(WGACore.DBATTRIB_DBKEY).toString());
        relativeURL = relativeURL.replaceAll("#KEY#", path.getContentKey().toString());

        StringBuffer url = new StringBuffer();
        url.append(getContextPath());
        url.append(relativeURL);
        return url.toString();
    }

    /**
     * retrieves a relative url from session attribute
     * WGACore.ATTRIB_VIRTUAL_CONTENT_URL to use instead of the default static
     * tml for vitual content in BI default is
     * "/statictml/#DBKEY#/dispVirtual/#CONTENTKEY_URL_MODE#" parameters
     * #DBKEY#, #CONTENTKEY_URL_MODE#, #CONTENTKEY_UNIQUE_MODE# and #STRUCTKEY#
     * are replaced by the corresponding values
     *
     * @param request
     * @param database
     * @param path
     * @param content
     * @return URL starting with getContextPath();
     * @throws WGAPIException
     */
    private String getVirtualContentURL(HttpServletRequest request, WGDatabase database, WGPRequestPath path, WGContent content) throws WGAPIException {
        // default URL used by old BI
        String defaultURL = "/statictml/#DBKEY#/dispVirtual/#CONTENTKEY_URL_MODE#";

        String relativeURL = null;
        if (request.getSession().getAttribute(WGACore.ATTRIB_VIRTUAL_CONTENT_URL) != null) {
            relativeURL = (String) request.getSession().getAttribute(WGACore.ATTRIB_VIRTUAL_CONTENT_URL);
        }
        else {
            relativeURL = defaultURL;
        }

        // replace variables in relative URL
        relativeURL = relativeURL.replaceAll("#DBKEY#", database.getAttribute(WGACore.DBATTRIB_DBKEY).toString());
        relativeURL = relativeURL.replaceAll("#CONTENTKEY_URL_MODE#", content.getContentKey(false).toString());
        relativeURL = relativeURL.replaceAll("#CONTENTKEY_UNIQUE_MODE#", content.getContentKey(true).toString());
        relativeURL = relativeURL.replaceAll("#STRUCTKEY#", content.getStructKey().toString());

        StringBuffer url = new StringBuffer();
        url.append(getContextPath());
        url.append(relativeURL);
        return url.toString();
    }

    /**
     * Method registerHit.
     *
     * @param userProfile
     * @param request
     * @param path
     * @param database
     * @param content
     */
    public void registerHit(WGUserProfile userProfile, WGDatabase database, WGContent content) {
        try {
            Integer statisticsMode = Integer.valueOf((String) _core.readPublisherOptionOrDefault(userProfile.getDatabase(), WGACore.DBATTRIB_PERSSTATMODE));
            if (statisticsMode == null || statisticsMode.intValue() != Constants.PERSSTATMODE_HIT) {
                return;
            }

            userProfile.addHit();
            userProfile.setLastAccess(new Date());

            if (database != null) {
                userProfile.setDBLogin(database.getSessionContext().getUser());
            }

            userProfile.save();
        }
        catch (Exception e) {
            _log.error("Unable to register hit in user profile", e);
        }
    }

    private void registerSession(WGUserProfile userProfile, HttpServletRequest request, HttpSession session, boolean created) {

        Integer statisticsMode = Integer.valueOf((String) _core.readPublisherOptionOrDefault(userProfile.getDatabase(), WGACore.DBATTRIB_PERSSTATMODE));
        if (!created && (statisticsMode == null || statisticsMode.intValue() == Constants.PERSSTATMODE_OFF)) {
            return;
        }

        try {
            userProfile.addNewSession(session);
            userProfile.setLastAccess(new Date());
            String userAgent = request.getHeader("User-Agent");
            if (userAgent != null) {
                userProfile.setClient(userAgent);
            }

            Enumeration langsIt = request.getLocales();
            List langs = new ArrayList();
            while (langsIt.hasMoreElements()) {
                langs.add(((Locale) langsIt.nextElement()).getLanguage());
            }
            userProfile.setLanguages(langs);

            userProfile.save();
        }
        catch (WGAPIException e) {
            _log.error("Unable to register session in user profile.", e);
        }
    }

    public TMLUserProfile fetchUserProfile(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, WGDatabase database, HttpSession session)
            throws WGAPIException {

        String domain = (String) database.getAttribute(WGACore.DBATTRIB_DOMAIN);
        if (domain == null) {
            return null;
        }

        // Tr to get pers db from domain
        WGDatabase persDB = null;
        try {
            persDB = _core.openPersonalisationDB(domain, session);
        }
        catch (WGAPIException e1) {
            _core.getLog().error("Error opening personalisation db for domain '" + domain + "'", e1);
            throw e1;
        }

        // Try to use content database as pers db or use an external self
        // personalisation db
        if (persDB == null) {
            if (database.hasFeature(WGDatabase.FEATURE_SELF_PERSONALIZABLE)) {
                persDB = database;
            }
            else {
                persDB = (WGDatabase) database.getAttribute(WGACore.DBATTRIB_EXTERNAL_SELF_PERSONALISATION_DB);
                if (persDB != null) {
                    if (!persDB.isSessionOpen()) {
                        persDB.openSession();
                    }
                }
                else {
                    return null;
                }
            }
        }

        // Try to retrieve previously stored user profile in session
        String wgpid = (String) session.getAttribute(SESSION_PROFILENAME_INDIVIDUALDB + database.getDbReference());
        if (wgpid != null) {
            WGUserProfile profile = persDB.getUserProfile(wgpid);
            if (profile != null) {
                TMLUserProfile tmlProfile = new TMLUserProfile(profile, getCore());
                request.setAttribute(WGACore.ATTRIB_PROFILE + database.getDbReference(), tmlProfile);
                return tmlProfile;
            }
        }

        // Fetch user profile using database's persmode. If not available we
        // take the default value for the option
        String persModeStr = (String) _core.readPublisherOptionOrDefault(database, WGACore.DBATTRIB_PERSMODE);
        Integer persMode;
        if (persModeStr != null) {
            persMode = Integer.valueOf(persModeStr);
        }
        // Backup for sure, which should not happen as the option is defined for
        // all databases
        else {
            persMode = Constants.PERSMODE_AUTO;
        }

        // If in Mode AUTO, the User Profile is retrieved automatically
        // (otherwise it is set in the login process)
        WGUserProfile userProfile = null;
        boolean created = false;
        if (persMode == Constants.PERSMODE_AUTO) {
            boolean secureMode = database.getBooleanAttribute(WGACore.DBATTRIB_SECURE_APP, false);
            String cookieName = COOKIE_WGPID;
            if (secureMode) {
                cookieName = COOKIE_SECURE_WGPID;
            }

            wgpid = this.findCookie(request.getCookies(), cookieName);
            if (wgpid != null) {
                userProfile = persDB.getUserProfile(wgpid);
            }

            if (userProfile == null) {
                userProfile = createUserProfile((String) request.getHeader("User-Agent"), persDB, wgpid, Constants.PERSMODE_AUTO);
                created = true;
            }

            if (userProfile != null && !userProfile.isDummy()) {
                Cookie wgpidCookie = new Cookie(cookieName, userProfile.getName());
                wgpidCookie.setPath("/");
                wgpidCookie.setSecure(secureMode);
                wgpidCookie.setMaxAge(60 * 60 * 24 * 365);
                response.addCookie(wgpidCookie);
            }
        }

        else if (persMode == Constants.PERSMODE_LOGIN) {
            if (database.getSessionContext().isAnonymous()) {
                // no profile for anonymous
                return null;
            }
            String userName = database.getSessionContext().getUser();
            userProfile = persDB.getUserProfile(userName);
            if (userProfile == null) {
                userProfile = createUserProfile((String) request.getHeader("User-Agent"), persDB, userName, Constants.PERSMODE_LOGIN);
                created =  true;
            }
        }

        // If valid user profile, set in session object and register new session
        if (userProfile != null && !userProfile.isDeleted()) {

            // Drop cache so we can be sure to be up-to-date with the backend
            // database
            // (Since backend changes - maybe from other cluster nodes - are not
            // registered for user profiles)
            userProfile.dropCache();

            session.setAttribute(SESSION_PROFILENAME_INDIVIDUALDB + database.getDbReference(), userProfile.getName());
            TMLUserProfile tmlProfile = new TMLUserProfile(userProfile, getCore());
            request.setAttribute(WGACore.ATTRIB_PROFILE + database.getDbReference(), tmlProfile);
            this.registerSession(userProfile, request, session, created);
            return tmlProfile;
        }
        else {
            session.removeAttribute(SESSION_PROFILENAME_INDIVIDUALDB + database.getDbReference());
            return null;
        }

    }

    private WGUserProfile createUserProfile(String userAgent, WGDatabase persDB, String wgpid, int persMode) throws WGAPIException {

        WGUserProfile userProfile;
        UserAgentVerifier userAgentVerifier = getCore().getUserAgentVerifier();
        if (userAgentVerifier.isValidUserAgent(userAgent) == true) {
            userProfile = persDB.createUserProfile(wgpid, persMode);
        }
        else {
            userProfile = persDB.getDummyProfile(wgpid);
        }

        if (userProfile != null && !userProfile.isDummy()) {
            TMLUserProfile.prepareNewProfile(userProfile);
            userProfile.save();
        }

        return userProfile;
    }

    private String findCookie(Cookie[] cookies, String cookieName) {

        if (cookies == null) {
            return null;
        }

        Cookie cookie;
        for (int idx = 0; idx < cookies.length; idx++) {
            cookie = cookies[idx];
            if (cookie.getName().equalsIgnoreCase(cookieName)) {
                return cookie.getValue();
            }
        }
        return null;

    }

    public static String getCompleteRequestURL(javax.servlet.http.HttpServletRequest request) {
        StringBuffer requestURL = request.getRequestURL();
        if (request.getQueryString() != null) {
            requestURL.append("?").append(request.getQueryString());
        }
        return requestURL.toString();
    }

    public static WGContent getContentByAnyKey(String contentKey, WGDatabase database, HttpServletRequest req) throws WGAPIException {

        if (contentKey == null || contentKey.trim().equals("")) {
            return null;
        }

        HttpSession session = req.getSession();
        boolean isBI = isBrowserInterface(session) || isAuthoringMode(database.getDbReference(), session);

        // Inner getContentByAnyKey
        return getContentByAnyKey(contentKey, database, new RequestLanguageChooser(database, req), isBI);

    }

    public static WGContent getContentByAnyKey(String contentKey, WGDatabase database, WGLanguageChooser languageChooser, boolean isBI) throws WGAPIException {
        try {
            URLID urlid = new URLID(contentKey, database);
            return getContentByAnyKey(urlid, database, languageChooser, isBI);
        }
        catch (WGIllegalArgumentException e) {
            return null;
        }
    }

    public static WGContent getContentByAnyKey(URLID id, WGDatabase database, WGLanguageChooser languageChooser, boolean isBI) throws WGAPIException {

        WGLanguage langObj;
        // Block with various attempts to search content by this key
        WGContent content = null;

        // Try to retrieve content via content key - Fastest way
        WGContentKey key = id.asContentKey();
        if (key != null) {
            content = database.getContentByKey(key);
            if (content != null) {
                return content;
            }
        }

        // Try to interpret struct key as unique name
        if (id.getSuffixVersion() == 0 && id.getLanguage() != null) {
            content = database.getContentByName(id.getResourceId(), id.getLanguage());
            if (content != null) {
                return content;
            }
        }

        // From here on we are sure to have no URLID of complete format. We will
        // use the complete id string from here on to make any sense of it.
        id.setCompleteFormat(false);
        String completeId = id.getCompleteId();

        // Try to use key as struct key only. If found, will try to find a
        // content for this struct from the languages list
        WGStructEntry entry = null;
        Object structKey = database.parseStructKey(completeId);
        if (structKey != null) {
            entry = database.getStructEntryByKey(structKey);
            if (entry != null) {
                content = languageChooser.selectContentForPage(entry, isBI);
                if (content != null) {
                    return content;
                }
            }
        }

        // Try to use key as name only
        content = languageChooser.selectContentForName(database, completeId, isBI);
        if (content != null) {
            return content;
        }

        // Try to retrieve via Name-Language syntax
        int dividerPos = completeId.lastIndexOf("-");
        if (content == null && dividerPos != -1) {
            String realName = completeId.substring(0, dividerPos);
            String realLanguage = completeId.substring(dividerPos + 1).toLowerCase();

            // Cutoff trailing suffix which might be there for browser
            // compatibility
            if (realLanguage.lastIndexOf(".") != -1) {
                realLanguage = realLanguage.substring(0, realLanguage.lastIndexOf("."));
            }

            if (realLanguage.equals(DEFAULT_LANGUAGE_TOKEN)) {
                realLanguage = database.getDefaultLanguage();
            }

            content = database.getContentByName(realName, realLanguage);
            if (content != null) {
                return content;
            }
        }

        // Last Try :-) Fetch by name only, so browser language
        // configuration cannot prevent you from fetching by name only
        // However, when the name is used by multiple language versions, the
        // first one is returned
        if (content == null) {
            content = database.getAnyContentByName(completeId);
            if (content != null) {
                return content;
            }
        }

        return null;

    }

    private void dispatchFileRequest(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws java.lang.Exception {

        WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);

        // Fetch database
        WGDatabase database = path.getDatabase();
        if (info != null) {
            info.setType(WGARequestInformation.TYPE_FILE);
            if (database != null) {
                info.setDatabase(database);
            }
        }

        // Parse container key - This may be a path when we have the /~file/
        // syntax. We use different parts depending on the type of container
        String containerKey = path.getContainerKey();
        List containerKeyElems = WGUtils.deserializeCollection(containerKey, "/");
        String containerKeyLastElement = (String) containerKeyElems.get(containerKeyElems.size() - 1);

        // Fetch the file container
        WGDocument fileContainer = database.getFileContainer(containerKeyLastElement);
        if (fileContainer == null) {

            // Container addressed by some kind of content key?
            WGContent content = getContentByAnyKey(containerKeyLastElement, database, request);

            // Container addressed by Title path?
            if (content == null) {
                TitlePathManager tpm = (TitlePathManager) database.getAttribute(WGACore.DBATTRIB_TITLEPATHMANAGER);
                if (tpm != null && tpm.isGenerateTitlePathURLs()) {
                    TitlePathManager.TitlePath url = tpm.parseTitlePathURL(containerKeyElems);
                    if (url != null) {
                        path.setTitlePathURL(url);
                        content = path.getContentByTitlePath(request);
                    }
                }
            }

            if (content == null || !content.mayBePublished(isBrowserInterface(request.getSession()) || isAuthoringMode(database.getDbReference(), request.getSession()), WGContent.DISPLAYTYPE_NONE)) {
                sendNoFileContainerNotification(path, request, response, database);
                return;
            }

            fileContainer = content;
        }

        if (info != null && fileContainer != null && fileContainer instanceof WGContent) {
            info.setContent((WGContent) fileContainer);
        }

        String fileName = path.getFileName();
        if (fileName == null || fileName.equals("")) {
            response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No file name in file URL: " + path.getCompleteURL());
            return;
        }

        ExternalFileServingConfig externalFileServingConfig = _core.getExternalFileServingConfig();

        if (externalFileServingConfig.isEnabled() && database.getBooleanAttribute(WGACore.DBATTRIB_EXTERNAL_FILE_SERVING_ENABLED, false)) {

            // check if file is anonymous accessible
            boolean isAnonymousAccessible = database.isAnonymousAccessible();

            if (isAnonymousAccessible) {
                // perform further document level checks
                if (fileContainer != null && fileContainer instanceof WGContent) {
                    // check status
                    if (!((WGContent) fileContainer).getStatus().equals(WGContent.STATUS_RELEASE)) {
                        isAnonymousAccessible = false;
                    }
                    // check readers
                    if (isAnonymousAccessible) {
                        isAnonymousAccessible = ((WGContent) fileContainer).getReaders().size() == 0;
                    }
                }
            }

            if (isAnonymousAccessible && fileContainer.getFileSize(fileName) >= externalFileServingConfig.getThreshold()) {
                // file is anonymous accessible and above external serving
                // threshold
                dispatchFileExternalImpl(externalFileServingConfig, path, request, response, database, fileContainer);
            }
            else {

                dispatchFileDefaultImpl(path, request, response, database, fileContainer);
            }
        }
        else {
            dispatchFileDefaultImpl(path, request, response, database, fileContainer);
        }

    }

    private void dispatchFileExternalImpl(ExternalFileServingConfig config, WGPRequestPath path, HttpServletRequest request, HttpServletResponse response, final WGDatabase database,
            final WGDocument fileContainer) throws WGAPIException, IOException, HttpErrorException, WGException {

        final String filename = path.getFileName();

        File dbRoot = config.getRootForDB(database.getDbReference());
        if (!dbRoot.exists()) {
            dbRoot.mkdir();
        }
        File externalCacheFolder = new File(dbRoot, fileContainer.getDocumentKey().replaceAll("/", ":"));
        if (!externalCacheFolder.exists()) {
            externalCacheFolder.mkdir();
        }

        if (!externalCacheFolder.exists()) {
            // fallback to normal dispatch
            _core.getLog().warn("Unable to create external file cache directory '" + externalCacheFolder.getAbsolutePath() + "'. Performing file dispatch in default mode.");
            dispatchFileDefaultImpl(path, request, response, database, fileContainer);
        }
        else {
            final File cachedFile = new File(externalCacheFolder, path.getFileName());

            if (isExternalCacheUpToDate(cachedFile, fileContainer, filename)) {
                // perform redirect
                response.sendRedirect(config.getRootURL() + database.getDbReference() + "/" + fileContainer.getDocumentKey().replaceAll("/", ":") + "/" + filename);
            }
            else {
                // cache file
                Thread cacheTask = new Thread() {

                    @Override
                    public void run() {
                        synchronized (WGPDispatcher.class.getName() + ".filecache." + cachedFile.getAbsolutePath().intern()) {
                            try {
                                database.openSession();
                                // perform synchronized up to date check
                                if (!isExternalCacheUpToDate(cachedFile, fileContainer, filename)) {

                                    File temp = new File(cachedFile.getParent(), UIDGenerator.generateUID() + ".tmp");
                                    WGDocument container = database.getDocumentByDocumentKey(fileContainer.getDocumentKey());
                                    InputStream in = null;
                                    OutputStream out = null;
                                    try {
                                        in = container.getFileData(filename);
                                        out = new FileOutputStream(temp);
                                        WGUtils.inToOut(in, out, 1024);
                                    }
                                    finally {
                                        if (in != null) {
                                            try {
                                                in.close();
                                            }
                                            catch (IOException e) {
                                            }
                                        }
                                        if (out != null) {
                                            try {
                                                out.close();
                                            }
                                            catch (IOException e) {
                                            }
                                        }
                                    }

                                    temp.renameTo(cachedFile);
                                    cachedFile.setLastModified(fileContainer.getFileLastModified(filename).getTime());
                                }
                            }
                            catch (Throwable e) {
                                _core.getLog().error("Unable to create cache for external file serving.", e);
                            }
                            finally {
                                WGFactory.getInstance().closeSessions();
                            }
                        }
                    }

                };

                cacheTask.start();

                dispatchFileDefaultImpl(path, request, response, database, fileContainer);
            }

        }
    }

    private boolean isExternalCacheUpToDate(File cachedFile, WGDocument fileContainer, String filename) throws WGAPIException {

        if (cachedFile.exists() && WGUtils.cutoffTimeMillis(cachedFile.lastModified()) == WGUtils.cutoffTimeMillis(fileContainer.getFileLastModified(filename).getTime())
                && cachedFile.length() == fileContainer.getFileSize(filename)) {
            return true;
        }
        else {
            return false;
        }
    }

    private void dispatchFileDefaultImpl(WGPRequestPath path, HttpServletRequest request, HttpServletResponse response, WGDatabase database, WGDocument fileContainer) throws IOException,
            WGAPIException, HttpErrorException, WGException {
        response.setDateHeader("Date", System.currentTimeMillis());

        // Set expiration time
        int fileExpirationMinutes = ((Integer) _core.readPublisherOptionOrDefault(database, WGACore.DBATTRIB_FILEEXPIRATION_MINUTES)).intValue();
        if (fileContainer instanceof WGContent && ((WGContent) fileContainer).getStatus().equals(WGContent.STATUS_DRAFT)) {
            fileExpirationMinutes = 0;
        }
       
        if (fileExpirationMinutes > 0) {
            int fileExpirationSeconds = fileExpirationMinutes * 60;
            response.setHeader("Cache-Control", "max-age=" + fileExpirationSeconds + ", must-revalidate");
        }

        String fileName = path.getFileName();

        // determine content type
        String contentType = this.getServletContext().getMimeType(fileName);
        if (contentType == null) {
            contentType = "application/octet-stream";
        }
        response.setContentType(contentType);

        // Create publishing file object, which will provide the data
        PublishingFile publishingFile = new PublishingFile(this, fileContainer, fileName);
        if (!publishingFile.isPublishable()) {
            throw new HttpErrorException(403, "Files from this container may not be published", path.getDatabaseKey());
        }
       
        // Optionally inject scaling information to file object
        String maxHeightStr = request.getParameter("maxheight");
        if (maxHeightStr != null) {
            try {
                int maxHeight = Integer.parseInt(maxHeightStr);
                publishingFile.setScaleMaxHeight(maxHeight);
            }
            catch (NumberFormatException e) {
                getCore().getLog().error("Unparseable scaling height: " + maxHeightStr);
            }
        }
       
        String maxWidthStr = request.getParameter("maxwidth");
        if (maxWidthStr != null) {
            try {
                int maxWidth = Integer.parseInt(maxWidthStr);
                publishingFile.setScaleMaxWidth(maxWidth);
            }
            catch (NumberFormatException e) {
                getCore().getLog().error("Unparseable scaling widthW: " + maxWidthStr);
            }
        }

        // determine lastModified
        // - last modified of binary response depends only on resource change
        // date
        // - last change date of textual response additionally depends on
        // character encoding change date
        long lastModified;
        if (isBinary(response)) {
            lastModified = publishingFile.getLastModifiedTime();
        }
        else {
            lastModified = Math.max(publishingFile.getLastModifiedTime(), _core.getCharacterEncodingLastModified());
            lastModified = Math.max(lastModified, _core.getDesignEncodingLastModified(database.getDbReference()));
        }

        // force download if requested by designer
        Boolean forceDownload = Boolean.parseBoolean(request.getParameter("forcedownload"));
        if (forceDownload) {
            response.setHeader("Content-disposition", "attachment");
        }
       
        // Handle browser cache
        if (browserCacheIsValid(request, lastModified)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }
        else {
            response.setDateHeader("Last-Modified", lastModified);
            response.setHeader("ETag", '"' + String.valueOf(lastModified) + '"');
        }

        // Allow accept ranges on all CS with optimized file handling and binary responses
        if (database.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA4_1 && isBinary(response)) {
            response.setHeader("Accept-Ranges", "bytes");
        }

        if (contentType.startsWith("application/")) {
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        }

        // Look if file is cached - If so, send it and exit
        FileCache fileCache = (FileCache) database.getAttribute(WGACore.DBATTRIB_FILECACHE);
        byte[] data = fileCache.getFile(publishingFile, lastModified);
        if (data != null) {
            try {

                // B000041DA
                ByteArrayDataSource dataIn = new ByteArrayDataSource(data, publishingFile.getFileName(), contentType);
                String designEncoding = (String) database.getAttribute(WGACore.DBATTRIB_DESIGN_ENCODING);

                if (designEncoding != null) {
                    writeData(dataIn, request, response, designEncoding, data.length, database.getDbReference(), true);
                }
                else {
                    writeData(dataIn, request, response, null, data.length, database.getDbReference(), true);
                }

            }
            catch (java.net.SocketException exc) {
                _log.warn("Dispatch of cached file request failed bc. of socket error: " + exc.getMessage());
            }
            catch (java.io.IOException exc) {
                if (!exc.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
                    _log.warn("Dispatch of cached file request failed bc. of IO error: " + exc.getMessage());
                }
            }
            return;
        }

        // In domino native implementations: Change to Master login to retrieve
        // data (Workaround for Domino API Bug)
        String databaseTypeName = database.getTypeName();
        if (databaseTypeName.equals("domino/wgacontentstore/local") || databaseTypeName.equals("domino/custom/local")) {
            WGFactory.getInstance().closeSessions();
            database = _core.openContentDB(path.getDatabaseKey(), null, true);
        }

        long fileSize = publishingFile.getFileSize();

        // Look if file size is below cache threshold - if so, collect data and
        // put into cache, then serve
        long threshold = fileCache.getThreshold();
        if (fileSize != -1 && threshold >= fileSize) {

            // Put into cache
            InputStream inputStream = publishingFile.getInputStream();
            try {
                ByteArrayOutputStream outCache = new ByteArrayOutputStream((int) fileSize);
                WGUtils.inToOut(inputStream, outCache, 2048);
                data = outCache.toByteArray();
                fileCache.putFile(publishingFile, data, lastModified);
            }
            catch (java.net.SocketException exc) {
                _log.warn("Caching of file request failed bc. of socket error: " + exc.getMessage());
            }
            catch (java.io.IOException exc) {
                if (!exc.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
                    _log.warn("Caching of file request failed bc. of IO error: " + exc.getMessage());
                }
            }
            finally {
                if (inputStream != null) {
                    try {
                        inputStream.close();
                    }
                    catch (Exception e) {
                    }
                }
            }

            // Writing from cache to out
            try {
                // B000041DA
                ByteArrayDataSource dataIn = new ByteArrayDataSource(data, publishingFile.getFileName(), contentType);
                String designEncoding = (String) database.getAttribute(WGACore.DBATTRIB_DESIGN_ENCODING);
                if (designEncoding != null) {
                    writeData(dataIn, request, response, designEncoding, data.length, database.getDbReference(), true);
                }
                else {
                    writeData(dataIn, request, response, null, data.length, database.getDbReference(), true);
                }
            }
            catch (java.net.SocketException exc) {
                _log.warn("Dispatch of file request failed bc. of socket error: " + exc.getMessage());
            }
            catch (java.io.IOException exc) {
                if (!exc.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
                    _log.warn("Dispatch of file request failed bc. of IO error: " + exc.getMessage());
                }
            }

            return;
        }

        // File is above threshold and not in cache - serve from database
        try {
            // B000041DA
            String designEncoding = (String) database.getAttribute(WGACore.DBATTRIB_DESIGN_ENCODING);
            if (designEncoding != null) {
                writeData(publishingFile, request, response, designEncoding, (int) fileSize, database.getDbReference(), database.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA4_1);
            }
            else {
                writeData(publishingFile, request, response, null, (int) fileSize, database.getDbReference(), database.getContentStoreVersion() >= WGDatabase.CSVERSION_WGA4_1);
            }
        }
        catch (java.net.SocketException exc) {
            _log.warn("Dispatch of file request failed bc. of socket error: " + exc.getMessage());
        }
        catch (java.io.IOException exc) {
            if (!exc.getClass().getName().equals("org.apache.catalina.connector.ClientAbortException")) {
                _log.warn("Dispatch of file request failed bc. of IO error: " + exc.getMessage());
            }
        }
    }

    private void dispatchResourceRequest(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws Exception {

        WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
        if (info != null) {
            info.setType(WGARequestInformation.TYPE_RESOURCE);
        }

        // determine mimeType
        String resourcePath = path.getResourcePath();
        String mimeType = this.getServletContext().getMimeType(resourcePath);
        if (mimeType == null) {
            mimeType = "application/octet-stream";
        }
        response.setContentType(mimeType);

        File file = null;
        boolean isTemporaryDownload = false;
        if (path.getPathCommand().equals(WGPRequestPath.PATHCMD_TEMP_DOWNLOAD)) {
            String tempFileName = path.getResourcePath().substring(path.getResourcePath().lastIndexOf("/") + 1);
            Map temporaryDownloads = (Map) request.getSession().getAttribute(SESSION_TEMPORARYDOWNLOADS);
            if (temporaryDownloads != null) {
                TemporaryDownload tempDownload = (TemporaryDownload) temporaryDownloads.get(tempFileName);
                if (tempDownload != null) {
                    file = tempDownload.getTempFile().getFile();
                    isTemporaryDownload = true;
                }
            }
        }
        else {
            file = new File(this.getServletContext().getRealPath("/"), path.getResourcePath());
        }

        if (file == null || !file.exists() || !file.isFile()) {
            throw new HttpErrorException(404, "File not found: " + path.getResourcePath(), null);
        }

        // / Set expiration time
        int fileExpirationMinutes = getCore().getWgaConfiguration().getCacheExpirationForStaticResources();
        if (fileExpirationMinutes > 0) {
            int fileExpirationSeconds = fileExpirationMinutes * 60;
            response.setHeader("Cache-Control", "max-age=" + fileExpirationSeconds + ", must-revalidate");
        }

        // determine lastModified
        // - last modified of binary response depends only on resource change
        // date
        // - last change date of textual response additionally depends on
        // character encoding change date
        long lastModified;
        if (isBinary(response)) {
            lastModified = file.lastModified();
        }
        else {
            lastModified = Math.max(file.lastModified(), _core.getCharacterEncodingLastModified());
        }
        if (browserCacheIsValid(request, lastModified)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }
        else {
            response.setDateHeader("Last-Modified", lastModified);
            response.setHeader("ETag", '"' + String.valueOf(lastModified) + '"');
        }

        if (mimeType.startsWith("application/")) {
            response.setHeader("Cache-Control", "must-revalidate, post-check=0, pre-check=0");
        }

        // Dispatch to file resource
        try {
            if (!"HEAD".equalsIgnoreCase(request.getMethod())) {
                DataSource in = null;
                int fileSize = 0;

                // We allow direct file dispatching only for temporary files. In
                // all other cases we use the servlet
                // context which will take care of file system security.
                if (isTemporaryDownload) {
                    response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
                    in = new URLDataSource(file.toURL());
                    fileSize = (int) file.length();
                }
                else {
                    in = new URLDataSource(this.getServletContext().getResource(resourcePath));
                }

                if (in == null) {
                    throw new HttpErrorException(404, "File not found: " + resourcePath, null);
                }

                // B000041DA
                // write data to response - use UTF-8 when reading characters -
                // WGA resources are UTF-8 encoded
                writeData(in, request, response, "UTF-8", fileSize, null, true);
            }
        }
        catch (java.net.SocketException exc) {
            _log.warn("Dispatch of resource request failed bc. of socket error: " + exc.getMessage());
        }
        catch (java.io.IOException exc) {
            _log.warn("Dispatch of resource request failed bc. of IO error: " + exc.getMessage());
        }
    }

    /**
     * writes the given data to the response based on response.getContentType()
     * either reader/writer (for textual content) or binary streams are used
     *
     * @param data
     *            - the data as inputstream to write - implicit closed after
     *            method call
     * @param request
     * @param response
     * @param characterEncoding
     *            - encoding to use when reading character based from given
     *            data, if null platform encoding is used
     * @throws IOException
     * @throws HttpErrorException
     */
    private void writeData(DataSource data, HttpServletRequest request, HttpServletResponse response, String characterEncoding, int size, String dbHint, boolean allowRanges) throws IOException,
            HttpErrorException {
       

        // Parse accept ranges if requested
        List<AcceptRange> ranges = new ArrayList<AcceptRange>();
        String rangeHeader = request.getHeader("Range");
        if (rangeHeader != null && allowRanges && isBinary(response) && size > 0) {
            if (rangeHeader.startsWith("bytes=")) {
                rangeHeader = rangeHeader.substring("bytes=".length());
                String[] subranges = rangeHeader.split("\\s*,\\s*");
                for (String r : subranges) {
                    Matcher matcher = ACCEPT_RANGE_PATTERN.matcher(r);
                    if (matcher.matches()) {
                        String from = matcher.group(1);
                        String to = matcher.group(2);
                        AcceptRange newRange;

                        try {
                            newRange = new AcceptRange(from != null ? Integer.parseInt(from) : -1, to != null ? Integer.parseInt(to) : -1);
                            if (newRange.from == -1) {
                                newRange.from = size - newRange.to;
                                newRange.to = size - 1;
                            }
                            else if (newRange.to == -1) {
                                newRange.to = size - 1;
                            }
                        }
                        catch (NumberFormatException e) {
                            response.addHeader("Content-Range", "bytes */" + size);
                            response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                            return;
                        }

                        if ((newRange.from == -1 && newRange.to == -1) || newRange.to > size) {
                            response.addHeader("Content-Range", "bytes */" + size);
                            response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                            return;
                        }
                        ranges.add(newRange);
                    }
                    else {
                        response.addHeader("Content-Range", "bytes */" + size);
                        response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                        return;
                    }
                }
            }
            else {
                response.addHeader("Content-Range", "bytes */" + size);
                response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
                return;
            }
        }

        if (ranges.isEmpty()) {
            // We can only set the raw length on binary resources bc.
            // transcoding textual response can change the size
            if (isBinary(response) && size > 0) {
                response.setContentLength(size);
            }

            if (!"HEAD".equalsIgnoreCase(request.getMethod())) {
                writeWholeData(data, response, characterEncoding, dbHint);
            }
           
        }
        else {
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            if (ranges.size() == 1) {
                AcceptRange r = ranges.get(0);
                response.addHeader("Content-Range", "bytes " + r.from + "-" + r.to + "/" + size);
                response.setContentLength(r.to - r.from + 1);
            }
            else {
                response.setContentType("multipart/byteranges; boundary=" + BYTERANGE_BOUNDARY);
            }
           
            if (!"HEAD".equalsIgnoreCase(request.getMethod())) {
                writeRangesData(data, ranges, response, dbHint, size);
            }
        }

    }

    private void writeWholeData(DataSource data, HttpServletResponse response, String characterEncoding, String dbHint) throws IOException, HttpErrorException, UnsupportedEncodingException {

        Reader reader = null;
        InputStream in = data.getInputStream();
        if (in == null) {
            throw new HttpErrorException(404, "File not found: " + data.getName(), dbHint);
        }

        try {
            if (!isBinary(response)) {
                // this is a textual reponse

                if (characterEncoding != null) {
                    // read data in given encoding
                    reader = new InputStreamReader(in, characterEncoding);
                }
                else {
                    // use platform encoding
                    reader = new InputStreamReader(in);
                }
                WGUtils.inToOut(reader, response.getWriter(), 2048);

            }
            else {
                WGUtils.inToOut(in, response.getOutputStream(), 2048);
            }
        }
        finally {
            if (reader != null) {
                try {
                    reader.close();
                }
                catch (IOException e) {
                }
            }
            if (in != null) {
                try {
                    in.close();
                }
                catch (IOException e) {
                }
            }
        }
    }

    private void writeRangesData(DataSource data, List<AcceptRange> ranges, HttpServletResponse response, String dbHint, long size) throws IOException, HttpErrorException, UnsupportedEncodingException {

        ServletOutputStream out = response.getOutputStream();
        for (AcceptRange range : ranges) {
            InputStream in = data.getInputStream();
            if (in == null) {
                throw new HttpErrorException(404, "File not found: " + data.getName(), dbHint);
            }
           
            if (ranges.size() != 1) {
                out.println();
                out.println("--" + BYTERANGE_BOUNDARY);
                out.println("Content-Type: " + data.getContentType());
                out.println("Content-Range: bytes " + range.from + "-" + range.to + "/" + size);
                out.println();
            }
           
            if (range.from > 0) {
                in.skip(range.from);
            }
   
            try {
                WGUtils.inToOutLimited(in, out, range.to - range.from + 1, 2048);
                out.flush();
            }
            finally {
                if (in != null) {
                    try {
                        in.close();
                    }
                    catch (IOException e) {
                    }
                }
            }
        }
       
        if (ranges.size() != 1) {
            out.println();
            out.print("--" + BYTERANGE_BOUNDARY + "--");
            out.flush();
        }
       
    }

    private void dispatchCssjsRequest(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws java.lang.Exception {

        WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
        if (info != null) {
            info.setType(WGARequestInformation.TYPE_SCRIPT);
        }

        // Fetch the database
        WGDatabase database = path.getDatabase();

        // Fetch the library
        String codeType;
        switch (path.getPathType()) {

            case WGPRequestPath.TYPE_CSS:
                codeType = WGScriptModule.CODETYPE_CSS;
                break;

            case WGPRequestPath.TYPE_JS:
                codeType = WGScriptModule.CODETYPE_JS;
                break;

            default:
                throw new HttpErrorException(500, "Invalid path type to dispatch a css/js request: " + path.getPathType(), path.getDatabaseKey());

        }

        WGCSSJSModule lib = database.getScriptModule(path.getCssjsKey(), codeType);
        if (lib == null) {
            throw new HttpErrorException(404, "No css/js resource of name " + path.getCssjsKey(), path.getDatabaseKey());
        }

        // determine mime type and encoding
        String mimeType;
        String libType = lib.getCodeType();
        if (libType.equals(WGCSSJSModule.CODETYPE_CSS)) {
            mimeType = "text/css";
        }
        else if (libType.equals(WGCSSJSModule.CODETYPE_JS)) {
            mimeType = "text/javascript";
        }
        else if (libType.equals(WGCSSJSModule.CODETYPE_VBS)) {
            mimeType = "text/vbscript";
        }
        else {
            mimeType = "text/" + libType;
        }
        response.setContentType(mimeType);

        // Set expiration time
        int fileExpirationMinutes = ((Integer) _core.readPublisherOptionOrDefault(database, WGACore.DBATTRIB_FILEEXPIRATION_MINUTES)).intValue();
        if (fileExpirationMinutes > 0) {
            int fileExpirationSeconds = fileExpirationMinutes * 60;
            response.setHeader("Cache-Control", "max-age=" + fileExpirationSeconds + ", must-revalidate");
        }

        // determine lastModified
        // - last modified of binary response depends only on resource change
        // date
        // - last change date of textual response additionally depends on
        // character encoding change date
        long lastModified;
        if (isBinary(response)) {
            lastModified = lib.getLastModified().getTime();
        }
        else {
            lastModified = Math.max(lib.getLastModified().getTime(), _core.getCharacterEncodingLastModified());
            lastModified = Math.max(lastModified, _core.getDesignEncodingLastModified(database.getDbReference()));
        }
        if (browserCacheIsValid(request, lastModified)) {
            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            return;
        }
        else {
            response.setDateHeader("Last-Modified", lastModified);
            response.setHeader("ETag", '"' + String.valueOf(lastModified) + '"');
        }

        // If this is a head request we are finished now
        if ("HEAD".equalsIgnoreCase(request.getMethod())) {
            return;
        }

        String code = lib.getCode();
        // response.setContentLength(code.length());

        try {
            java.io.Writer out = response.getWriter();
            out.write(code);
        }
        catch (java.net.SocketException exc) {
            _log.warn("Dispatch of css/js request failed bc. of socket error: " + exc.getMessage());
        }
        catch (java.io.IOException exc) {
            _log.warn("Dispatch of css/js request failed bc. of IO error: " + exc.getMessage());
        }
    }

    /**
     * @see GenericServlet#init(ServletConfig)
     */
    public void init(ServletConfig config) throws ServletException {

        super.init(config);
        _log = Logger.getLogger("wga.publisher");
        Thread.currentThread().setName("WGPDispatcher.init");

        this.getServletContext().setAttribute(WGACore.ATTRIB_DISPATCHER, this);
        this._core = (WGACore) getServletContext().getAttribute(WGACore.ATTRIB_CORE);
        if (this._core == null) {
            _log.fatal("Could not connect to WGACore");
        }

        _tmlDebugger = new WebTMLDebugger();
        _variousServerOptionReader = _core.getConfigOptionReader("/serverOptions", WGAServerOptionsModuleType.class, VariousModuleDefinition.class);

        this.setServePages(true);
        _log.debug("WebGate Anywhere Publisher initialized");

    }

    public WGACore getCore() {
        return _core;
    }

    /**
     * @see GenericServlet#destroy()
     */
    public void destroy() {

        shutdown();
        super.destroy();
    }

    public void shutdown() {
        this.setServePages(false);

    }

    public String getLoginURL(HttpServletRequest req, WGDatabase database, String sourceURL) throws UnsupportedEncodingException {

        // / Retrieve LoginPage publisher option. If it is not set it defaults
        // to /login.jsp�
        String url = (String) database.getAttribute(WGACore.DBATTRIB_LOGIN_PAGE);
        if (url == null || url.equals("")) {
            url = "/login.jsp";
        }

        StringBuffer loginURL = qualifyWGAURL(url, req, database);

        String parameterIntroducor = "?";
        if (url.indexOf("?") != -1) {
            parameterIntroducor = "&";
        }

        loginURL.append(parameterIntroducor).append("domain=").append(database.getAttribute(WGACore.DBATTRIB_DOMAIN).toString()).append("&redirect=").append(
                java.net.URLEncoder.encode(sourceURL, getCore().getCharacterEncoding()));

        return loginURL.toString();

    }

    public String getAdminLoginURL(HttpServletRequest req, String sourceURL) throws UnsupportedEncodingException {

        StringBuffer loginURL = new StringBuffer();
        loginURL.append(getPublisherURL(req)).append("/login.jsp");

        String parameterIntroducor = "?";
        if (loginURL.indexOf("?") != -1) {
            parameterIntroducor = "&";
        }

        loginURL.append(parameterIntroducor).append("domain=").append(WGACore.DOMAIN_ADMINLOGINS).append("&redirect=").append(java.net.URLEncoder.encode(sourceURL, getCore().getCharacterEncoding()));

        return loginURL.toString();

    }

    /**
     * Takes a URL, and qualifies it to be a complete path, given the following
     * schema: - If the url contains double slashes "//" it is considered to be
     * a complete path already and returned unmodified - If the url starts with
     * a slash "/", it is considered to be starting with a database key and it
     * is only completed by the application context path - If the url does not
     * start with a slash, it is considered to be a relative path for the given
     * database. It is completed to the context path and the dbs database key
     *
     * @param url
     *            The url to qualify
     * @param req
     *            A request object, used to determine the application context
     *            path
     * @param database
     *            A database, used to determine a database key
     * @return A string buffer containing the qualified URL. It can be used to
     *         add further information to the path
     */
    public StringBuffer qualifyWGAURL(String url, HttpServletRequest req, WGDatabase database) {
        StringBuffer loginURL = new StringBuffer();

        // If this is no complete url, we will prepend the publisher url and
        // conditionally dbkey, if the LoginPage does not begin with "/"
        if (url.indexOf("//") == -1) {

            loginURL.append(getPublisherURL(req, false));
            if (!url.startsWith("/")) {
                if (database == null) {
                    throw new IllegalArgumentException("Cannot qualify URL '" + url + "' when database parameter is not given");
                }
                loginURL.append("/").append(database.getDbReference()).append("/");
            }
        }

        loginURL.append(url);
        return loginURL;
    }

    public String getPublisherURL(javax.servlet.http.HttpServletRequest request, boolean absolute) {
        if (request != null && absolute) {

            String protocol = request.getProtocol().substring(0, request.getProtocol().indexOf("/")).toLowerCase();
            if (protocol.equals("http") && request.isSecure()) {
                protocol = "https";
            }
           
            int port = request.getServerPort();           
            if (port != -1) {               
                if (protocol.equals("http") && port == 80) {
                    port = -1;
                } else if (protocol.equals("https") && port == 443) {
                    port = -1;
                }
            }

            return protocol + "://" + request.getServerName() + (port != -1 ? ":" + port : "") + request.getContextPath();
        }
        else {
            return request.getContextPath();
        }
    }

    public String getPublisherURL(javax.servlet.http.HttpServletRequest request) {
        return this.getPublisherURL(request, false);
    }

    private void dispatchStaticTmlRequest(WGPRequestPath path, javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws java.lang.Exception {

        // do not static requests
        WGARequestInformation info = (WGARequestInformation) request.getAttribute(WGARequestInformation.REQUEST_ATTRIBUTENAME);
        if (info != null) {
            info.setType(WGARequestInformation.TYPE_STATIC);
        }

        // Fetch the database
        WGDatabase database = path.getDatabase();
        String contentKey = path.getContentKey();
        String jspName = path.getResourcePath();

        if (database != null) {
            WGContent content = null;
            LanguageBehaviour langBehaviour = LanguageBehaviourTools.retrieve(database);

            // Determine the content for this request
            if (contentKey != null) {
                content = getContentByAnyKey(contentKey, database, request);
                if (content == null) {
                    if (request.getQueryString() != null && request.getQueryString().toLowerCase().indexOf("login") != -1) {
                        sendRedirect(response, getLoginURL(request, database, path.getCompleteURL()));
                    }
                    else {
                        throw new HttpErrorException(404, "No content of name/id " + contentKey, path.getDatabaseKey());
                    }
                    return;
                }
                if (!content.isVisible() && !isBrowserInterface(request.getSession())) {
                    throw new HttpErrorException(404, "No content of name/id " + contentKey, path.getDatabaseKey());
                }
            }
            else {
                WGLanguage lang = langBehaviour.requestSelectDatabaseLanguage(database, request);
                content = database.getDummyContent(lang.getName());
            }

            // Test browsability of content
            if (!content.isDummy() && getBrowsingSecurity(database) <= BrowsingSecurity.NO_BROWSING) {
                throw new HttpErrorException(java.net.HttpURLConnection.HTTP_FORBIDDEN, "Browsing not allowed in database '" + path.getDatabaseKey() + "'", path.getDatabaseKey());
            }

            request.setAttribute(WGACore.ATTRIB_MAINCONTEXT, content);
            request.setAttribute(WGACore.ATTRIB_MEDIAKEY, database.getAttribute(WGACore.DBATTRIB_DEFAULT_MEDIAKEY));

        }

        // Set context attributes for jsps
        String completeURL = path.getCompleteURL();
        request.setAttribute(WGACore.ATTRIB_WGPPATH, this.getPublisherURL(request));
        request.setAttribute(WGACore.ATTRIB_TAGIDS, WGUtils.createSynchronizedMap());
        request.setAttribute(WGACore.ATTRIB_TMLCONTEXTS, WGUtils.createSynchronizedMap());
        request.setAttribute(WGACore.ATTRIB_REQUESTURL, completeURL);
        request.setAttribute(WGACore.ATTRIB_REQUESTTYPE, REQUESTTYPE_STATICTML);

        String mimeType = null;
        if (contentKey != null) {
            mimeType = this.getServletContext().getMimeType(jspName);
        }
        else {
            mimeType = this.getServletContext().getMimeType(request.getRequestURI());
        }
        if (mimeType == null) {
            mimeType = "text/html";
        }

        request.setAttribute(WGACore.ATTRIB_MIMETYPE, mimeType);
        response.setContentType(mimeType);

        String targetJSP = jspName + ".jsp";

        if (targetJSP != null) {
            if (!"HEAD".equalsIgnoreCase(request.getMethod())) {
                this.getServletContext().getRequestDispatcher(targetJSP).include(request, response);
            }
        }
        else {
            throw new HttpErrorException(500, "no static tml page: " + targetJSP, path.getDatabaseKey());
        }

        // Eventually do redirect
        if (request.getAttribute(WGACore.ATTRIB_REDIRECT) != null) {
            response.reset();
            response.sendRedirect(String.valueOf(request.getAttribute(WGACore.ATTRIB_REDIRECT)));
        }
    }
   
    public int getBrowsingSecurity(WGDatabase db) {
       
        String securityStr = (String) db.getAttribute(WGACore.DBATTRIB_BROWSING_SECURITY);
        if (securityStr != null) {
            return Integer.parseInt(securityStr);
        }
       
        String allowBrowsing = (String) db.getAttribute(WGACore.DBATTRIB_ALLOW_BROWSING);
        if (allowBrowsing != null && Boolean.parseBoolean(allowBrowsing) == false) {
            return BrowsingSecurity.NO_BROWSING;
        }
       
        return BrowsingSecurity.FULL_ACCESS;
       
               
    }



    /**
     * @see GenericServlet#getServletInfo()
     */
    public String getServletInfo() {
        return WGACore.getReleaseString();
    }

    /**
     * Gets the contextPath
     *
     * @return Returns a String
     */
    public String getContextPath() {
        return _contextPath;
    }

    /**
     * Sets the contextPath
     *
     * @param contextPath
     *            The contextPath to set
     */
    public void setContextPath(String contextPath) {
        this._contextPath = contextPath;
    }

    /**
     * Gets the listenPort
     *
     * @return Returns a int
     */
    public int getListenPort() {
        return _listenPort;
    }

    /**
     * Returns the servePages.
     *
     * @return boolean
     */
    public boolean isServePages() {
        return _servePages;
    }

    /**
     * @deprecated use isAdminLoggedIn(HttpServletRequest) instead
     * @param session
     * @return
     */
    public boolean isAdminLoggedIn(HttpSession session) {
        return isAdminLoggedIn(session, null);
    }

    /**
     * @deprecated use isAdminLoggedIn(HttpServletRequest) instead
     * @param session
     * @param request
     * @return
     */
    public boolean isAdminLoggedIn(HttpSession session, HttpServletRequest request) {
        if (request != null) {
            return getCore().isAdminLoggedIn(request);
        }
        else {
            return getCore().isAdminLoggedIn(session);
        }
    }

    public boolean isAdminLoggedIn(HttpServletRequest request) {
        return getCore().isAdminLoggedIn(request);
    }

    /**
     * Sets the servePages.
     *
     * @param servePages
     *            The servePages to set
     */
    public void setServePages(boolean servePages) {
        this._servePages = servePages;
    }

    public static String buildVirtualLink(WGContent content, ServletRequest request, String mediakey, String layout) throws WGAPIException {

        // External urls are just put out without modification
        String vlinkType = content.getVirtualLinkType();
        if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_EXTERNAL)) {
            return content.getVirtualLink();
        }

        // Build base url
        WGPRequestPath path = (WGPRequestPath) request.getAttribute(WGACore.ATTRIB_REQUESTPATH);
        StringBuffer url = new StringBuffer();
        url.append(path.getPublisherURL()).append("/");
        String dbKey = content.getDatabase().getAttribute(WGACore.DBATTRIB_DBKEY).toString();
        url.append(dbKey).append("/");

        // Vary detail path by link type
        if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_INTERNAL_FILE)) {
            url.append("file/");
            url.append(content.getContentKey(false).toString());
            url.append("/");
            url.append(content.getVirtualLink());
            return url.toString();
        }
        else if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_CONTENT)) {

            // Extract content key
            List elements = WGUtils.deserializeCollection(content.getVirtualLink(), "/");
            String contentKey = (String) elements.get(elements.size() - 1);

            // If available append media and layout keys
            if (mediakey != null) {
                url.append(mediakey).append("/");
            }
            if (layout != null) {
                url.append(layout).append("/");
            }
            url.append(contentKey);
            return url.toString();
        }
        else if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_FILE)) {

            // Extract file container and filename information
            List elements = WGUtils.deserializeCollection(content.getVirtualLink(), "/");
            if (elements.size() < 2) {
                throw new IllegalArgumentException("Virtual link of type '" + vlinkType + "' in " + content.getDocumentKey() + "' has too few elements (< 2)");
            }

            String containerName = (String) elements.get(elements.size() - 2);
            String fileName = (String) elements.get(elements.size() - 1);

            // Build url
            url.append("file/");
            url.append(containerName);
            url.append("/");
            url.append(fileName);
            return url.toString();
        }
        else if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_EXTERNAL_FILE)) {
            List elements = WGUtils.deserializeCollection(content.getVirtualLink(), "/");
            if (elements.size() < 2) {
                throw new IllegalArgumentException("Virtual link of type '" + vlinkType + "' in " + content.getDocumentKey() + "' has too few elements (< 2)");
            }

            String containerName = (String) elements.get(0);
            String fileName = (String) elements.get(1);

            // Build url
            url.append("file/");
            url.append(containerName);
            url.append("/");
            url.append(fileName);
            return url.toString();
        }
        else if (vlinkType.equals(WGContent.VIRTUALLINKTYPE_UNIQUENAME)) {
            String uname = content.getVirtualLink();
            url.append(uname);
            return url.toString();
        }

        // Fallback. If unknown link type, just put out virtual link
        else {
            return content.getVirtualLink();
        }

    }

    /**
     * @param code
     * @param message
     * @param dbHint
     * @deprecated instead throw HttpErrorException directly
     * @throws HttpErrorException
     */
    public void sendError(int code, String message, String dbHint) throws HttpErrorException {
        throw new HttpErrorException(code, message, dbHint);
    }

    /**
     * @param code
     * @param message
     * @deprecated instead throw HttpErrorException directly
     * @throws HttpErrorException
     */
    public void sendError(int code, String message) throws HttpErrorException {
        sendError(code, message, null);
    }

    public synchronized String addTemporaryDownload(HttpSession session, TemporaryFile file) {

        String name = UIDGenerator.generateUID();
        Map temporaryDownloads = (Map) session.getAttribute(SESSION_TEMPORARYDOWNLOADS);
        if (temporaryDownloads == null) {
            temporaryDownloads = new TransientMap(new HashMap());
            session.setAttribute(SESSION_TEMPORARYDOWNLOADS, temporaryDownloads);
        }

        TemporaryDownload tempDownload = new TemporaryDownload(name, file);
        temporaryDownloads.put(name, tempDownload);
        return name;

    }

    public synchronized String addTemporaryDownload(HttpSession session, File file) throws IOException {

        InputStream in = new FileInputStream(file);
        TemporaryFile tempFile = new TemporaryFile(file.getName(), in, WGFactory.getTempDir());
        return addTemporaryDownload(session, tempFile);

    }

    private boolean browserCacheIsValid(HttpServletRequest request, long lastModified) {

        String currentETag = String.valueOf(lastModified);
        String browserETagsStr = (String) request.getHeader("If-None-Match");
        if (browserETagsStr != null) {
            Iterator browserETags = WGUtils.deserializeCollection(browserETagsStr, ",", true, new Character('"')).iterator();
            while (browserETags.hasNext()) {
                String rawETag = (String) browserETags.next();
                String eTag = rawETag.substring(rawETag.indexOf('"') + 1, rawETag.lastIndexOf('"'));
                if (eTag.equals(currentETag)) {
                    return true;
                }
            }
        }

        long modSince = request.getDateHeader("If-Modified-Since");
        if (modSince != -1 && modSince >= WGUtils.cutoffTimeMillis(lastModified)) {
            return true;
        }

        return false;

    }

    private boolean isBinary(HttpServletResponse response) {
        String mimeType = response.getContentType();
        if (mimeType != null && mimeType.toLowerCase().indexOf("text") != -1) {
            return false;
        }
        else {
            return true;
        }
    }

}
TOP

Related Classes of de.innovationgate.wgpublisher.WGPDispatcher$TemporaryDownload

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.