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    }