/* * * Copyright (C) 2007-2015 Licensed to the Comunes Association (CA) under * one or more contributor license agreements (see COPYRIGHT for details). * The CA licenses this file to you under the GNU Affero General Public * License version 3, (the "License"); you may not use this file except in * compliance with the License. This file is part of kune. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package cc.kune.core.server.rack; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.waveprotocol.box.server.CoreSettings; import org.waveprotocol.box.server.persistence.file.FileUtils; import org.waveprotocol.box.server.rpc.ServerRpcProvider; import org.waveprotocol.box.server.waveserver.LucenePerUserWaveViewHandlerImpl; import com.google.gwt.logging.server.RemoteLoggingServiceImpl; import com.google.inject.Binder; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Module; import com.google.inject.grapher.GrapherModule; import com.google.inject.grapher.InjectorGrapher; import com.google.inject.grapher.graphviz.GraphvizModule; import com.google.inject.grapher.graphviz.GraphvizRenderer; import com.google.inject.name.Names; import cc.kune.core.client.errors.DefaultException; import cc.kune.core.server.error.ServerException; import cc.kune.core.server.mbean.MBeanRegister; import cc.kune.core.server.rack.dock.Dock; import cc.kune.core.server.rack.dock.RequestMatcher; import cc.kune.core.server.rack.utils.RackHelper; import cc.kune.core.server.scheduler.CustomJobFactory; import cc.kune.core.server.searcheable.SearchEngineServletFilter; public class RackServletFilter implements Filter { public static class DockChain implements FilterChain { private final Iterator<Dock> iterator; public DockChain(final Iterator<Dock> iterator) { this.iterator = iterator; } @Override public void doFilter(final ServletRequest request, final ServletResponse response) throws IOException, ServletException, DefaultException { Dock dock = null; boolean matched = false; final String relative = RackHelper.getRelativeURL(request); while (!matched && iterator.hasNext()) { dock = iterator.next(); matched = dock.matches(relative); } if (matched) { execute(dock.getFilter(), request, response); } } private void execute(final Filter filter, final ServletRequest request, final ServletResponse response) throws IOException, ServletException { // log.debug("RACK FILTER: " + filter.getClass().getSimpleName()); filter.doFilter(request, response, this); } } public static final String INJECTOR_ATTRIBUTE = Injector.class.getName() + "Child"; public static final String INJECTOR_PARENT_ATTRIBUTE = ServerRpcProvider.INJECTOR_ATTRIBUTE; private static final Log LOG = LogFactory.getLog(RackServletFilter.class); private static final String MODULE_PARAMETER = RackModule.class.getName(); private static final String SYMBOL_MAPS_ON_DEV = "target/kune-1.0.1-SNAPSHOT/WEB-INF/deploy/wse/symbolMaps"; private static final String SYMBOL_MAPS_ON_PRODUCTION = "symbolMapsWse"; private List<Dock> docks; private List<RequestMatcher> excludes; private boolean initialized; private Injector injector; private Rack rack; @Override public void destroy() { for (final Dock dock : docks) { dock.getFilter().destroy(); } } @Override public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { final String relative = RackHelper.getRelativeURL(request); for (final RequestMatcher matcher : excludes) { if (matcher.matches(relative)) { LOG.info("Excluded (from Guice): " + relative); chain.doFilter(request, response); return; } } LOG.debug("REQUEST: " + relative); final FilterChain newChain = new DockChain(docks.iterator()); newChain.doFilter(request, response); } @Override protected void finalize() throws Throwable { super.finalize(); stopContainerListeners(rack.getListeners(), injector); } private RackModule getModule(final FilterConfig filterConfig) { final String moduleName = getModuleName(filterConfig); try { final Class<?> clazz = Class.forName(moduleName); final RackModule module = (RackModule) clazz.newInstance(); return module; } catch (final Exception e) { throw new ServerException("couldn't instantiate the rack module", e); } } private String getModuleName(final FilterConfig filterConfig) { final String moduleName = filterConfig.getInitParameter(MODULE_PARAMETER); if (moduleName == null) { throw new ServerException("Rack module name can't be null!"); } return moduleName; } @SuppressWarnings("unused") private void graph(final String filename, final Injector kuneInjector) { try { final PrintWriter out = new PrintWriter(new File(filename), "UTF-8"); final Injector injector = Guice.createInjector(new GrapherModule(), new GraphvizModule()); final GraphvizRenderer renderer = injector.getInstance(GraphvizRenderer.class); renderer.setOut(out).setRankdir("TB"); injector.getInstance(InjectorGrapher.class).of(kuneInjector).graph(); } catch (final IOException e) { LOG.debug("Exception creation guice graph", e); } } @Override public void init(final FilterConfig filterConfig) throws ServletException { if (initialized) { throw new ServerException("Trying to init RackServletFilter twice"); } LOG.debug("INITIALIZING RackServletFilter..."); final RackModule module = getModule(filterConfig); final RackBuilder builder = new RackBuilder(); module.configure(builder); rack = builder.getRack(); injector = (Injector) filterConfig.getServletContext().getAttribute(INJECTOR_PARENT_ATTRIBUTE); final Module otherGuiceModule = new Module() { @Override public void configure(final Binder binder) { // Here, other objects that are not register in Rack binder.bind(SearchEngineServletFilter.class).toInstance( (SearchEngineServletFilter) filterConfig.getServletContext().getAttribute( SearchEngineServletFilter.SEARCH_ENGINE_FILTER_ATTRIBUTE)); } }; final Injector kuneChildInjector = installInjector(filterConfig, rack, injector, otherGuiceModule); final CustomJobFactory jobFactory = kuneChildInjector.getInstance(CustomJobFactory.class); jobFactory.setInjector(kuneChildInjector); startContainerListeners(rack.getListeners(), kuneChildInjector); docks = rack.getDocks(); excludes = rack.getExcludes(); initFilters(filterConfig); LOG.debug("INITIALIZATION DONE!"); // kuneChildInjector.getInstance(CustomImportServlet.class).init( // kuneChildInjector.getInstance(KuneProperties.class)); LOG.debug("Register some mbeans objects"); kuneChildInjector.getInstance(MBeanRegister.class); LOG.debug("Configure remote logging"); final String dir = FileUtils.isDirExistsAndNonEmpty(SYMBOL_MAPS_ON_PRODUCTION) ? "symbolMapsWse/" : FileUtils.isDirExistsAndNonEmpty(SYMBOL_MAPS_ON_DEV) ? SYMBOL_MAPS_ON_DEV : null; if (dir != null) { kuneChildInjector.getInstance(RemoteLoggingServiceImpl.class).setSymbolMapsDirectory(dir); } // We need to close wave Lucene indexer properly String searchType = injector.getInstance( Key.get(String.class, Names.named(CoreSettings.SEARCH_TYPE))); if ("lucene".equals(searchType)) { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { LOG.debug("Closing wave indexer"); injector.getInstance(LucenePerUserWaveViewHandlerImpl.class).close(); } }); } initialized = true; // Uncomment to generate the graph // graph("docs/wave-guice-graph.dot", injector); // graph("docs/kune-guice-graph.dot", kuneChildInjector); } private void initFilters(final FilterConfig filterConfig) throws ServletException { for (final Dock dock : docks) { dock.getFilter().init(filterConfig); } } private Injector installInjector(final FilterConfig filterConfig, final Rack rack, final Injector waveChildInjector, final Module otherModule) { final List<Module> guiceModules = rack.getGuiceModules(); guiceModules.add(otherModule); final Injector childInjector = waveChildInjector.createChildInjector(guiceModules); filterConfig.getServletContext().setAttribute(INJECTOR_ATTRIBUTE, childInjector); return childInjector; } private void startContainerListeners(final List<Class<? extends ContainerListener>> listenerClasses, final Injector injector) { LOG.debug("STARTING CONTAINER LISTENERS..."); for (final Class<? extends ContainerListener> listenerClass : listenerClasses) { final ContainerListener listener = injector.getInstance(listenerClass); listener.start(); } } private void stopContainerListeners(final List<Class<? extends ContainerListener>> listenerClasses, final Injector injector) { LOG.info("STOPPING CONTAINER LISTENERS..."); for (final Class<? extends ContainerListener> listenerClass : listenerClasses) { final ContainerListener listener = injector.getInstance(listenerClass); listener.stop(); } } }