/*
* Copyright (C) 2014 Civilian Framework.
*
* Licensed under the Civilian License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.civilian-framework.org/license.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.civilian.context.servlet;
import java.io.IOException;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.UnavailableException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.civilian.Application;
import org.civilian.Context;
import org.civilian.Response;
import org.civilian.Version;
import org.civilian.internal.Logs;
import org.civilian.util.Check;
/**
* AppServlet is a servlet which is mapped to the path of an {@link Application}.
* When it receives a request, it constructs a Request and Response object
* wrapping HttpServletRequest and HttpServletResponse and then invokes
* the application.<p>
* For every Civilian application within a {@link Context} exists an own AppServlet instance.
* Usually the servlets are dynamically created and registered, using the
* information of the application config.
*/
public class AppServlet implements Servlet
{
private static final String APP_ID_PARAMETER = "app.id";
/**
* Constructor used when the servlet is defined in web.xml and
* created by the servlet container.
*/
public AppServlet()
{
}
/**
* Constructor used when the servlet is created by ServletContainer and
* dynamically registered.
*/
public AppServlet(Application app)
{
app_ = Check.notNull(app, "app");
}
/**
* Called by the servlet container.
*/
@Override public void init(ServletConfig config) throws ServletException
{
servletConfig_ = config;
servletContext_ = config.getServletContext();
if (app_ == null)
initApplication();
}
/**
* Obtain a pointer to the application, when we were created via web.xml definition.
*/
private void initApplication() throws ServletException
{
String appId = servletConfig_.getInitParameter(APP_ID_PARAMETER);
if (appId == null)
throw new UnavailableException("no init parameter '" + APP_ID_PARAMETER + "' defined");
ServletContextAdapter adapter = ServletContextAdapter.getInstance(servletContext_);
if (adapter == null)
throw new UnavailableException("ServletContext is not available: did you register " + ContextListener.class.getName() + " as listener in your web.xml?");
app_ = adapter.getApplication(appId);
if (app_ == null)
throw new UnavailableException("no application with id '" + appId + "' defined");
}
/**
* Returns the servlet config.
*/
@Override public ServletConfig getServletConfig()
{
return servletConfig_;
}
/**
* Returns a servlet info string.
*/
@Override public String getServletInfo()
{
return getClass().getSimpleName() + " v" + Version.VALUE;
}
/**
* Processes the servlet request.
*/
@Override public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException,
ServletException
{
HttpServletRequest httpRequest;
HttpServletResponse httpResponse;
try
{
httpRequest = (HttpServletRequest)servletRequest;
httpResponse = (HttpServletResponse)servletResponse;
}
catch(ClassCastException e)
{
Logs.SERVLET.error("invalid servlet request and response: " +
servletRequest.getClass().getName() + ", " +
servletResponse.getClass().getName(), e);
return;
}
// don't serve anything if we are closed
if (app_ == null)
{
httpResponse.sendError(Response.Status.NOT_FOUND);
return;
}
ServletRequestAdapter request;
try
{
request = isMultiPartRequest(httpRequest) ?
new MpRequestAdapter(app_, httpRequest) :
new SpRequestAdapter(app_, httpRequest);
// will register with the request
new ServletResponseAdapter(request, httpResponse);
}
catch(Exception e)
{
Logs.SERVLET.error(null, e);
httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
app_.process(request);
}
private boolean isMultiPartRequest(HttpServletRequest httpRequest)
{
String contentType = httpRequest.getContentType();
return (contentType != null) && contentType.toLowerCase().startsWith("multipart/form-data");
}
/**
* Called by the servlet context when the context shuts down.
* Calls close().
*/
@Override public void destroy()
{
close();
}
/**
* Clears the reference to the app.
* Called by the servlet container when the context is closed.
*/
public void close()
{
app_ = null;
}
private Application app_;
private ServletConfig servletConfig_;
private ServletContext servletContext_;
}