package org.smartly.packages.cms.impl.handlers.servlets.pages;
import com.mongodb.DBObject;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.jetty.util.resource.Resource;
import org.smartly.Smartly;
import org.smartly.packages.cms.SmartlyHttpCms;
import org.smartly.packages.cms.impl.cms.page.mongodb.entities.CMSPageEntity;
import org.smartly.packages.cms.impl.cms.page.mongodb.services.CMSPageEntityService;
import org.smartly.commons.logging.Level;
import org.smartly.commons.logging.Logger;
import org.smartly.commons.util.*;
import org.smartly.packages.http.SmartlyHttp;
import org.smartly.packages.http.impl.WebServer;
import org.smartly.packages.http.impl.util.ServletUtils;
import org.smartly.packages.http.impl.util.vtool.Cookies;
import org.smartly.packages.http.impl.util.vtool.Req;
import org.smartly.packages.velocity.impl.VLCManager;
import org.smartly.packages.velocity.impl.vtools.EngineTool;
import org.smartly.packages.velocity.impl.vtools.toolbox.VLCToolbox;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.*;
/**
* Servlet for site file parsing.
*/
public class PagesServlet
extends HttpServlet {
public static String PATH = "/pages/";
public static String ENDPOINT = PATH + "*";
private static final String MIME_HTML = "text/html";
private static final Set<String> _extensions = new HashSet<String>(Arrays.asList(new String[]{".vhtml"}));
private Resource _baseResource;
private WebServer _server;
public PagesServlet() {
}
public PagesServlet(final Object params) {
}
// --------------------------------------------------------------------
// p u b l i c
// --------------------------------------------------------------------
public void setServer(final WebServer server) {
_server = server;
_server.getServletExtensions().addAll(_extensions);
}
public void setBaseResource(final Resource base) {
_baseResource = base;
}
public void setResourceBase(final String resourceBase) {
try {
this.setBaseResource(Resource.newResource(resourceBase));
} catch (Exception e) {
this.getLogger().warning(e.toString());
throw new IllegalArgumentException(resourceBase);
}
}
protected void doGet(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
this.handle(request, response);
}
protected void doPost(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
this.handle(request, response);
}
protected void handle(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
this.handleInternal(request, response);
}
// ------------------------------------------------------------------------
// p r i v a t e
// ------------------------------------------------------------------------
private Logger getLogger() {
return SmartlyHttpCms.getCMSLogger();
}
private void handleInternal(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException, IOException {
final String resourcePath = ServletUtils.getResourcePath(request);
final String lang = Req.getLang(request);
final String pageId = resourcePath.replace(PATH, "");
final DBObject page = CMSPageEntityService.getPage(pageId);
if (null!=page) {
//-- CMS --//
final String template = SmartlyHttp.readFile( CMSPageEntity.getTemplate(page, lang) );
if (null == page || !StringUtils.hasText(template)) {
ServletUtils.notFound404(response);
return;
}
// eval template
final byte[] output = this.merge(template, resourcePath, lang, page, request, response);
// write body
ServletUtils.writeResponse(response, DateUtils.now().getTime(), MIME_HTML, output);
return;
} else if (isVelocity(resourcePath)) {
//-- .vhtml --//
final Resource resource = ServletUtils.getResource(_baseResource, null, resourcePath);
if (!resource.exists()) {
ServletUtils.notFound404(response);
return;
}
// parse resource
final byte[] output = this.merge(resource, request, response);
// write body
ServletUtils.writeResponse(response, DateUtils.now().getTime(), MIME_HTML, output);
return;
}
ServletUtils.notFound404(response);
}
private byte[] merge(final String templateText,
final String url,
final String lang,
final DBObject page,
final HttpServletRequest request,
final HttpServletResponse response) {
try {
// session context
final HttpSession session = request.getSession(true);
if (session.isNew()) {
session.setAttribute("velocity-context", new HashMap<String, Object>());
}
final Map<String, Object> sessionContext = (Map<String, Object>) session.getAttribute("velocity-context");
final VelocityEngine engine = getEngine();
// execution context
final VelocityContext context = new VelocityContext(sessionContext, this.createInnerContext(
url, request, response));
context.put(EngineTool.NAME, new EngineTool(url, engine, context)); // $engine
// creates new context page
final org.smartly.packages.cms.impl.cms.page.CMSPage ctxPage = new org.smartly.packages.cms.impl.cms.page.CMSPage(lang, page);
context.put("page", ctxPage);
//-- eval velocity template --//
final String result;
if (null != engine) {
result = VLCManager.getInstance().evaluateText(engine, url, templateText, context);
} else {
result = VLCManager.getInstance().evaluateText(url, templateText, context);
}
if (StringUtils.hasText(result)) {
return result.getBytes();
}
} catch (Throwable t) {
this.getLogger().log(Level.SEVERE, FormatUtils.format(
"ERROR MERGING TEMPLATE FOR RESOURCE '{0}': {1}",
url, ExceptionUtils.getRealMessage(t)), t);
}
return new byte[0];
}
private byte[] merge(final Resource resource,
final HttpServletRequest request,
final HttpServletResponse response) {
try {
// session context
final HttpSession session = request.getSession(true);
if (session.isNew()) {
session.setAttribute("velocity-context", new HashMap<String, Object>());
}
final Map<String, Object> sessionContext = (Map<String, Object>) session.getAttribute("velocity-context");
final VelocityEngine engine = getEngine();
// execution context
final VelocityContext context = new VelocityContext(sessionContext, this.createInnerContext(
resource.getName(), request, response));
//-- eval velocity template --//
final String text = new String(ByteUtils.getBytes(resource.getInputStream()), Smartly.getCharset());
final String result;
if (null != engine) {
result = VLCManager.getInstance().evaluateText(engine, resource.getName(), text, context);
} else {
result = VLCManager.getInstance().evaluateText(resource.getName(), text, context);
}
if (StringUtils.hasText(result)) {
return result.getBytes();
}
} catch (Throwable t) {
this.getLogger().log(Level.SEVERE, FormatUtils.format(
"ERROR MERGING TEMPLATE FOR RESOURCE '{0}': {1}",
resource.getName(), ExceptionUtils.getRealMessage(t)), t);
}
return new byte[0];
}
private VelocityContext createInnerContext(final String url,
final HttpServletRequest request,
final HttpServletResponse response) {
final VelocityContext result = new VelocityContext(VLCToolbox.getInstance().getToolsContext());
//-- "$req" tool --//
result.put(Req.NAME, new Req(url, request));
//-- "$cookies" tool --//
result.put(Cookies.NAME, new Cookies(request, response));
return result;
}
// --------------------------------------------------------------------
// S T A T I C
// --------------------------------------------------------------------
private static VelocityEngine __engine;
private static VelocityEngine getEngine() throws Exception {
if (null == __engine) {
__engine = VLCManager.getInstance().getEngine().getNativeEngine();
}
return __engine;
}
private static boolean isVelocity(final String path) {
final String ext = PathUtils.getFilenameExtension(path, true);
return _extensions.contains(ext);
}
}