package org.curriki.xwiki.servlet;
import com.xpn.xwiki.XWiki;
import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.user.api.XWikiUser;
import com.xpn.xwiki.render.XWikiVelocityRenderer;
import com.xpn.xwiki.web.XWikiResponse;
import com.xpn.xwiki.web.XWikiRequest;
import com.xpn.xwiki.web.XWikiEngineContext;
import com.xpn.xwiki.web.XWikiServletRequest;
import com.xpn.xwiki.web.Utils;
import com.xpn.xwiki.web.XWikiURLFactory;
import com.xpn.xwiki.web.XWikiServletContext;
import com.xpn.xwiki.web.XWikiServletResponse;
import com.noelios.restlet.ext.servlet.ServletConverter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.curriki.xwiki.servlet.restlet.router.BaseRouter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xwiki.container.servlet.ServletContainerInitializer;
import org.xwiki.container.servlet.ServletContainerException;
import org.xwiki.container.Container;
import org.xwiki.context.Execution;
/**
*/
public class RestletServlet extends BaseServlet {
protected ServletConverter converter;
private static final Log LOG = LogFactory.getLog(RestletServlet.class);
@Override protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
try {
converter = new ServletConverter(getServletContext());
XWikiContext context = getXWikiContext(req, res);
converter.getContext().getAttributes().put("XWikiContext", context);
try {
converter.setTarget(new BaseRouter(converter.getContext()));
converter.service(req, res);
} finally {
cleanupComponents();
}
} catch (XWikiException e) {
throw new ServletException(e);
}
}
private Object generateDummy(Class someClass) {
ClassLoader loader = someClass.getClassLoader();
InvocationHandler handler = new InvocationHandler() {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
};
Class[] interfaces = new Class[] {someClass};
return Proxy.newProxyInstance(loader, interfaces, handler);
}
protected XWikiContext getXWikiContext(HttpServletRequest req, HttpServletResponse res) throws XWikiException, ServletException {
XWikiEngineContext engine;
ServletContext sContext = null;
try {
sContext = getServletContext();
} catch (Exception ignore) { }
if (sContext != null) {
engine = new XWikiServletContext(sContext);
} else {
// use fake server context (created as dynamic proxy)
ServletContext contextDummy = (ServletContext)generateDummy(ServletContext.class);
engine = new XWikiServletContext(contextDummy);
}
XWikiRequest request = new XWikiServletRequest(req);
XWikiResponse response = new XWikiServletResponse(res);
XWikiContext context = Utils.prepareContext("", request, response, engine);
context.setMode(XWikiContext.MODE_SERVLET);
context.setDatabase("xwiki");
// We need to initialize the new components for Velocity to work
initializeContainerComponent(context);
XWiki xwiki = XWiki.getXWiki(context);
XWikiURLFactory urlf = xwiki.getURLFactoryService().createURLFactory(context.getMode(), context);
context.setURLFactory(urlf);
// TODO: Fix velocity init in servlet
// XWikiVelocityRenderer.prepareContext(context);
xwiki.prepareResources(context);
String username = "XWiki.XWikiGuest";
XWikiUser user = context.getWiki().checkAuth(context);
if (user != null) {
username = user.getUser();
}
context.setUser(username);
// Give servlet "programming" rights
XWikiDocument rightsDoc = context.getWiki().getDocument("XWiki.XWikiPreferences", context);
context.put("sdoc", rightsDoc);
if (context.getDoc() == null) {
context.setDoc(new XWikiDocument("Fake", "Document"));
}
context.put("ajax", new Boolean(true));
return context;
}
protected void initializeContainerComponent(XWikiContext context)
throws ServletException
{
// Initialize the Container fields (request, response, session).
// Note that this is a bridge between the old core and the component architecture.
// In the new component architecture we use ThreadLocal to transport the request,
// response and session to components which require them.
// In the future this Servlet will be replaced by the XWikiPlexusServlet Servlet.
ServletContainerInitializer containerInitializer =
(ServletContainerInitializer) Utils.getComponent(ServletContainerInitializer.class);
try {
containerInitializer.initializeRequest(context.getRequest().getHttpServletRequest(),
context);
containerInitializer.initializeResponse(context.getResponse().getHttpServletResponse());
containerInitializer.initializeSession(context.getRequest().getHttpServletRequest());
} catch (ServletContainerException e) {
throw new ServletException("Failed to initialize Request/Response or Session", e);
}
}
protected void cleanupComponents()
{
Container container = (Container) Utils.getComponent(Container.class);
Execution execution = (Execution) Utils.getComponent(Execution.class);
// We must ensure we clean the ThreadLocal variables located in the Container and Execution
// components as otherwise we will have a potential memory leak.
container.removeRequest();
container.removeResponse();
container.removeSession();
execution.removeContext();
}
}