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.
063 // At this spot we could use req.getProperties().put(..) instead of request.setAttribute(..) but at the other
064 // spots (setViewModel() and view()) we could not inject a ContainerRequest but only a javax.ws.rs.core.Request
065 // and Request does not provide a getProperties() method. And we neither can cast a Request into a
066 // ContainerRequest 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 }