/* * Copyright 2013 eXo Platform SAS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package juzu.impl.bridge.spi.servlet; import juzu.impl.asset.AssetServer; import juzu.impl.bridge.Bridge; import juzu.impl.bridge.BridgeConfig; import juzu.impl.bridge.BridgeContext; import juzu.impl.bridge.module.ApplicationBridge; import juzu.impl.bridge.module.ModuleContextImpl; import juzu.impl.bridge.provided.ProvidedBridge; import juzu.impl.bridge.spi.web.Handler; import juzu.impl.common.Completion; import juzu.impl.common.JUL; import juzu.impl.common.Tools; import juzu.impl.common.Logger; import juzu.impl.common.SimpleMap; import juzu.impl.compiler.CompilationException; import juzu.impl.fs.spi.ReadFileSystem; import juzu.impl.fs.spi.war.WarFileSystem; import juzu.impl.inject.spi.Injector; import juzu.impl.inject.spi.InjectorProvider; import juzu.impl.inject.spi.spring.SpringInjector; import juzu.impl.resource.ResourceResolver; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ public class ServletBridge extends HttpServlet { /** The resource bundle name. */ public static final String BUNDLE_NAME = "juzu.resource_bundle"; /** . */ private String path; /** . */ private BridgeConfig bridgeConfig; /** . */ private BridgeContext bridgeContext; /** . */ private Bridge bridge; /** . */ private Handler handler; /** . */ private String bundleName; /** . */ private Logger servletLogger; /** . */ ServletApplicationContext applicationContext; Bridge getBridge() { return bridge; } @Override public void init() throws ServletException { // String path = null; ServletRegistration reg = getServletContext().getServletRegistration(getServletName()); for (String mapping : reg.getMappings()) { if ("/".equals(mapping)) { path = ""; break; } else if ("/*".equals(mapping)) { throw new UnsupportedOperationException("Implement me"); } else if (mapping.endsWith("/*")) { path = mapping.substring(0, mapping.length() - 2); } else { throw new UnsupportedOperationException("Should not be possible"); } } if (path == null) { throw new ServletException("Juzu servlet should be mounted on an url pattern"); } // Logger servletLogger = JUL.getLogger(ServletBridge.class + "." + getServletConfig().getServletName()); // final ServletConfig servletConfig = getServletConfig(); // BridgeConfig config; try { config = new BridgeConfig(servletLogger, new SimpleMap<String, String>() { @Override protected Iterator<String> keys() { return BridgeConfig.NAMES.iterator(); } @Override public String get(Object key) { if (BridgeConfig.APP_NAME.equals(key)) { return getApplicationName(servletConfig); } else if (BridgeConfig.INJECT.equals(key)) { // Cascade: // 1/ portlet init param // 2/ serlvet context init param String inject = servletConfig.getInitParameter((String)key); if (inject == null) { inject = servletConfig.getServletContext().getInitParameter((String)key); } return inject; } else if (BridgeConfig.REQUEST_ENCODING.equals(key)) { return servletConfig.getServletContext().getInitParameter((String)key); } else { return null; } } }); } catch (Exception e) { throw wrap(e); } // if (config.name == null) { throw new ServletException("No application configured"); } // Create and configure bridge InjectorProvider injectorProvider = config.injectorProvider; if (injectorProvider == null) { throw new UnavailableException("No inject implementation selected"); } else { servletLogger.info("Using inject implementation " + injectorProvider.getValue()); } // BridgeContext bridgeContext = new AbstractBridgeContext() { final ResourceResolver resolver = new ResourceResolver() { public URL resolve(String uri) { try { return getServletContext().getResource(uri); } catch (MalformedURLException e) { return null; } } }; public ReadFileSystem<?> getResourcePath() { return WarFileSystem.create(getServletContext(), "/WEB-INF/"); } public ReadFileSystem<?> getClassPath() { return WarFileSystem.create(getServletContext(), "/WEB-INF/classes/"); } public ClassLoader getClassLoader() { return getServletContext().getClassLoader(); } public String getInitParameter(String name) { return getServletContext().getInitParameter(name); } public ResourceResolver getResolver() { return resolver; } public Object getAttribute(String key) { return getServletContext().getAttribute(key); } public void setAttribute(String key, Object value) { getServletContext().setAttribute(key, value); } }; // this.bridgeConfig = config; this.handler = null; this.path = path; this.bundleName = servletConfig.getInitParameter(BUNDLE_NAME); this.servletLogger = servletLogger; this.bridgeContext = bridgeContext; } static ServletException wrap(Throwable e) { return e instanceof ServletException ? (ServletException)e : new ServletException("Could not find an application to start", e); } /** * Returns the application name to use using the <code>juzu.app_name</code> init parameter of the portlet deployment * descriptor. Subclass can override it to provide a custom application name. * * @param config the portlet config * @return the application name */ protected String getApplicationName(ServletConfig config) { return config.getInitParameter("juzu.app_name"); } private void refresh() throws Exception { if (bridge == null) { // ResourceResolver resolver = new ResourceResolver() { public URL resolve(String uri) { try { return getServletConfig().getServletContext().getResource(uri); } catch (MalformedURLException e) { return null; } } }; // Injector injector = bridgeConfig.injectorProvider.get(); if (injector instanceof SpringInjector) { SpringInjector springInjector = (SpringInjector)injector; Object parent = getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT"); if (parent != null) { springInjector.setParent(parent); } } // ModuleContextImpl module = (ModuleContextImpl)getServletContext().getAttribute("juzu.module"); if (module == null) { getServletContext().setAttribute("juzu.module", module = new ModuleContextImpl(servletLogger, bridgeContext, resolver)); } // Get asset server AssetServer server = (AssetServer)getServletContext().getAttribute("asset.server"); if (server == null) { server = new AssetServer(); getServletContext().setAttribute("asset.server", server); } // if (injector.isProvided()) { bridge = new ProvidedBridge(bridgeContext, this.bridgeConfig, server, resolver, injector); } else { bridge = new ApplicationBridge(module, bridgeContext, this.bridgeConfig, server, resolver, injector); } } // Completion<Boolean> refresh = bridge.refresh(); if (refresh.isFailed()) { throw refresh.getCause(); } else if (refresh.get()) { if (handler != null) { Tools.safeClose(handler); handler = null; applicationContext = null; } } // if (handler == null) { this.handler = new Handler(bridge); this.applicationContext = new ServletApplicationContext(getServletContext().getClassLoader(), bundleName); } } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // ServletRequestContext ctx = new ServletRequestContext( bridgeConfig.name, bridgeConfig.requestEncoding, req, resp, path, bridgeContext.getRunMode()); // ServletWebBridge bridge = new ServletWebBridge(this, ctx); // Do we need to send a server resource ? if (ctx.getRequestPath().length() > 1 && !ctx.getRequestPath().startsWith("/WEB-INF/")) { URL url = getServletContext().getResource(ctx.getRequestPath()); if (url != null) { RequestDispatcher dispatcher = getServletContext().getNamedDispatcher("default"); dispatcher.include(bridge.getRequestContext().req, bridge.getResponse()); return; } } // try { refresh(); } catch (CompilationException e) { ctx.send(e); return; } catch (Exception e) { throw wrap(e); } // try { handler.handle(bridge); } catch (Throwable throwable) { throw wrap(throwable); } } @Override public void destroy() { /* if (module != null) { if (module.release()) { // Should dispose module (todo later) } } */ if (handler != null) { Tools.safeClose(handler); this.handler = null; } } }