// This file is part of AceWiki.
// Copyright 2008-2013, AceWiki developers.
//
// AceWiki is free software: you can redistribute it and/or modify it under the terms of the GNU
// Lesser General Public License as published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
//
// AceWiki is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
// even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with AceWiki. If
// not, see http://www.gnu.org/licenses/.
package ch.uzh.ifi.attempto.acewiki;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import nextapp.echo.app.ApplicationInstance;
import nextapp.echo.webcontainer.WebContainerServlet;
import ch.uzh.ifi.attempto.base.APE;
import ch.uzh.ifi.attempto.base.LoggerContext;
/**
* This servlet class is used by the web server to start AceWiki.
* In order to run the AceWiki servlet, a web application archive (WAR) file has to be created.
* See the <a href="{@docRoot}/README.txt">README file</a> and the
* <a href="{@docRoot}/web.xml">web.xml example file</a>.
*<p>
* An APE should be accessible for the server, either directly installed on local or using socket
* or web service. See the documentation of {@link APE} for more information.
*<p>
* For larger ontologies it might be necessary to adjust the stack and heap size, for example by
* the following Java VM arguments:
* <code>-Xmx400m -Xss4m</code>
*
* @author Tobias Kuhn
* @author Yu Changyuan
*/
public class AceWikiServlet extends WebContainerServlet {
private static final long serialVersionUID = -7342857942059126499L;
private final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass());
private LoggerContext loggerContext;
private Backend backend;
private Map<String, String> parameters;
private String backendName;
/**
* Creates a new AceWiki servlet object.
*/
public AceWikiServlet() {
}
/**
* Init the AceWiki servlet, get its Backend from ServletContext according
* to its config in web.xml or create backend if no 'backend' parameter
* exist.
*
* @param config servlet config.
*/
public void init(ServletConfig config) throws ServletException {
parameters = getInitParameters(config);
if (loggerContext == null) {
loggerContext = new LoggerContext("syst", "syst", "0");
}
loggerContext.propagateWithinThread();
org.slf4j.MDC.put("type", "appl");
backendName = config.getInitParameter("backend");
if (backendName != null) {
log.info("use backend: {}", backendName);
while (true) {
backend = (Backend) config.getServletContext().getAttribute(backendName);
if (backend != null) break;
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
break;
}
}
// merge backend parameters
Map<String, String> p = parameters;
parameters = new HashMap<String,String>();
parameters.putAll(backend.getParameters());
parameters.putAll(p);
} else {
log.info("create backend");
APE.setParameters(parameters);
backend = new Backend(parameters);
}
super.init(config);
}
public ApplicationInstance newApplicationInstance() {
loggerContext.propagateWithinThread();
org.slf4j.MDC.put("type", "appl");
log.info("new application instance: {}", parameters.get("ontology"));
return new AceWikiApp(backend, parameters);
}
protected void process(HttpServletRequest request, HttpServletResponse response) throws
IOException, ServletException {
String params = "";
String p;
boolean hasInternalParams = false;
// URLs of the form "...?showpage=ArticleName" can be used to access an article directly.
// For the internal processing "...?page=ArticleName" is used.
p = request.getParameter("showpage");
if (p != null) params += "&page=" + p;
if (request.getParameter("page") != null) hasInternalParams = true;
// URLs of the form "...?showlang=Language" can be used to access a specific language
// version of the wiki. For the internal processing "...?lang=Language" is used.
p = request.getParameter("showlang");
if (p != null) params += "&lang=" + p;
if (request.getParameter("lang") != null) hasInternalParams = true;
if (!request.getSession().isNew() && params.length() > 0) {
response.sendRedirect(
response.encodeRedirectURL("?sid=ExternalEvent" + params)
);
}
if (params.length() == 0 && hasInternalParams && request.getParameter("sid") == null) {
response.sendRedirect(response.encodeRedirectURL("."));
}
org.slf4j.MDC.put("type", "fail");
try {
super.process(request, response);
} catch (RuntimeException | IOException | ServletException ex) {
loggerContext.propagateWithinThread();
log.error("fatal error", ex);
ex.printStackTrace();
throw ex;
}
}
@SuppressWarnings("rawtypes")
static Map<String, String> getInitParameters(ServletConfig config) {
Map<String, String> initParameters = new HashMap<String, String>();
Enumeration paramEnum = config.getInitParameterNames();
while (paramEnum.hasMoreElements()) {
String n = paramEnum.nextElement().toString();
initParameters.put(n, config.getInitParameter(n));
}
Enumeration contextParamEnum = config.getServletContext().getInitParameterNames();
while (contextParamEnum.hasMoreElements()) {
String n = contextParamEnum.nextElement().toString();
initParameters.put("context:" + n, config.getServletContext().getInitParameter(n));
}
// Set default parameters:
if (initParameters.get("context:apecommand") == null) {
initParameters.put("context:apecommand", "ape.exe");
}
if (initParameters.get("context:logdir") == null) {
initParameters.put("context:logdir", "logs");
}
if (initParameters.get("context:datadir") == null) {
initParameters.put("context:datadir", "data");
}
return initParameters;
}
}