001 package de.deepamehta.plugins.webactivator; 002 003 import de.deepamehta.core.osgi.PluginActivator; 004 import de.deepamehta.core.service.event.ServiceRequestFilterListener; 005 006 import com.sun.jersey.api.view.Viewable; 007 // ### TODO: hide Jersey internals. Move to JAX-RS 2.0. 008 import com.sun.jersey.spi.container.ContainerRequest; 009 010 import org.thymeleaf.TemplateEngine; 011 import org.thymeleaf.TemplateProcessingParameters; 012 import org.thymeleaf.context.AbstractContext; 013 import org.thymeleaf.context.WebContext; 014 import org.thymeleaf.resourceresolver.IResourceResolver; 015 import org.thymeleaf.templateresolver.TemplateResolver; 016 017 import org.osgi.framework.Bundle; 018 019 import javax.servlet.ServletContext; 020 import javax.servlet.http.HttpServletRequest; 021 import javax.servlet.http.HttpServletResponse; 022 023 import javax.ws.rs.Path; 024 import javax.ws.rs.core.Context; 025 026 import java.io.InputStream; 027 import java.util.logging.Logger; 028 029 030 031 // Note: although no REST service is provided the plugin is annotated as a root resource class. 032 // Otherwise we can't receive JAX-RS context injections (HttpServletRequest). 033 @Path("/webactivator") 034 public class WebActivatorPlugin extends PluginActivator implements ServiceRequestFilterListener { 035 036 // ------------------------------------------------------------------------------------------------------- Constants 037 038 private static String ATTR_CONTEXT = "de.deepamehta.plugins.webactivator.Context"; 039 040 // ---------------------------------------------------------------------------------------------- Instance Variables 041 042 private TemplateEngine templateEngine; 043 044 @Context private HttpServletRequest request; 045 @Context private HttpServletResponse response; 046 @Context private ServletContext servletContext; 047 048 private Logger logger = Logger.getLogger(getClass().getName()); 049 050 // -------------------------------------------------------------------------------------------------- Public Methods 051 052 053 054 // ******************************** 055 // *** Listener Implementations *** 056 // ******************************** 057 058 059 060 @Override 061 public void serviceRequestFilter(ContainerRequest containerRequest) { 062 // Note: we don't operate on the passed ContainerRequest but on the injected HttpServletRequest. At this spot we 063 // could use containerRequest.getProperties().put(..) instead of request.setAttribute(..) but at the other spots 064 // (viewData() and view()) we could not inject a ContainerRequest but only a javax.ws.rs.core.Request and 065 // Request does not provide a getProperties() method. And we neither can cast a Request into a ContainerRequest 066 // as the injected Request is actually a proxy object (in order to deal with multi-threading). 067 request.setAttribute(ATTR_CONTEXT, new WebContext(request, response, servletContext)); 068 } 069 070 071 072 // === 073 074 public TemplateEngine getTemplateEngine() { 075 if (templateEngine == null) { 076 throw new RuntimeException("The template engine for " + this + " is not initialized. " + 077 "Don't forget calling initTemplateEngine() from your plugin's init() hook."); 078 } 079 // 080 return templateEngine; 081 } 082 083 084 085 // ----------------------------------------------------------------------------------------------- Protected Methods 086 087 protected void initTemplateEngine() { 088 TemplateResolver templateResolver = new TemplateResolver(); 089 templateResolver.setResourceResolver(new BundleResourceResolver(bundle)); 090 // 091 templateEngine = new TemplateEngine(); 092 templateEngine.setTemplateResolver(templateResolver); 093 } 094 095 protected void viewData(String name, Object value) { 096 context().setVariable(name, value); 097 } 098 099 protected Viewable view(String templateName) { 100 return new Viewable(templateName, context()); 101 } 102 103 // ------------------------------------------------------------------------------------------------- Private Methods 104 105 private AbstractContext context() { 106 return (AbstractContext) request.getAttribute(ATTR_CONTEXT); 107 } 108 109 // --------------------------------------------------------------------------------------------------- Inner Classes 110 111 private class BundleResourceResolver implements IResourceResolver { 112 113 private Bundle bundle; 114 115 private BundleResourceResolver(Bundle bundle) { 116 this.bundle = bundle; 117 } 118 119 @Override 120 public String getName() { 121 return "BundleResourceResolver"; 122 } 123 124 @Override 125 public InputStream getResourceAsStream(TemplateProcessingParameters params, String resourceName) { 126 try { 127 return bundle.getResource(resourceName).openStream(); 128 } catch (Exception e) { 129 return null; 130 } 131 } 132 } 133 }