info.magnolia.cms.filters.FilterManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for info.magnolia.cms.filters.FilterManagerImpl.java

Source

/**
 * This file Copyright (c) 2011-2012 Magnolia International
 * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
 *
 *
 * This file is dual-licensed under both the Magnolia
 * Network Agreement and the GNU General Public License.
 * You may elect to use one or the other of these licenses.
 *
 * This file is distributed in the hope that it will be
 * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
 * implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
 * Redistribution, except as permitted by whichever of the GPL
 * or MNA you select, is prohibited.
 *
 * 1. For the GPL license (GPL), you can redistribute and/or
 * modify this file under the terms of the GNU General
 * Public License, Version 3, as published by the Free Software
 * Foundation.  You should have received a copy of the GNU
 * General Public License, Version 3 along with this program;
 * if not, write to the Free Software Foundation, Inc., 51
 * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * 2. For the Magnolia Network Agreement (MNA), this file
 * and the accompanying materials are made available under the
 * terms of the MNA which accompanies this distribution, and
 * is available at http://www.magnolia-cms.com/mna.html
 *
 * Any modifications to this file must keep this entire header
 * intact.
 *
 */
package info.magnolia.cms.filters;

import info.magnolia.cms.core.Content;
import info.magnolia.cms.core.HierarchyManager;
import info.magnolia.cms.servlets.ClasspathSpool;
import info.magnolia.cms.util.ObservationUtil;
import info.magnolia.context.MgnlContext;
import info.magnolia.context.SystemContext;
import info.magnolia.jcr.node2bean.Node2BeanException;
import info.magnolia.jcr.node2bean.Node2BeanProcessor;
import info.magnolia.module.ModuleManager;
import info.magnolia.repository.RepositoryConstants;

import java.util.Collections;

import javax.inject.Inject;
import javax.inject.Singleton;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;

import org.apache.commons.lang.StringUtils;

/**
 * Default {@link FilterManager} implementation; uses node2bean and observation
 * to maintain the filter chain configured at {@value #SERVER_FILTERS}.
 */
@Singleton
public class FilterManagerImpl implements FilterManager {

    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(FilterManagerImpl.class);

    private final EventListener filtersEventListener = new EventListener() {
        @Override
        public void onEvent(EventIterator arg0) {
            MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
                @Override
                public void doExec() {
                    resetRootFilter();
                }
            }, true);
        }
    };

    private final ModuleManager moduleManager;
    private final SystemContext systemContext;
    private final MgnlFilterDispatcher filterDispatcher = new MgnlFilterDispatcher();
    private final Object resetLock = new Object();
    private FilterConfig filterConfig;
    private final Node2BeanProcessor nodeToBean;

    @Inject
    public FilterManagerImpl(ModuleManager moduleManager, SystemContext systemContext,
            Node2BeanProcessor nodeToBean) {
        this.moduleManager = moduleManager;
        this.systemContext = systemContext;
        this.nodeToBean = nodeToBean;
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // remember this config
        this.filterConfig = filterConfig;
        MgnlContext.doInSystemContext(new MgnlContext.VoidOp() {
            @Override
            public void doExec() {
                try {
                    MgnlFilter filter = createRootFilter();
                    initRootFilter(filter, FilterManagerImpl.this.filterConfig);
                    filterDispatcher.replaceTargetFilter(filter);
                } catch (ServletException e) {
                    log.error("Error initializing filters", e);
                    return;
                }
                if (!isSystemUIMode()) {
                    startObservation();
                }
            }
        }, true);
    }

    @Override
    public void destroy() {
        MgnlFilter filter = filterDispatcher.replaceTargetFilter(null);
        destroyRootFilter(filter);
    }

    @Override
    public MgnlFilterDispatcher getFilterDispatcher() {
        return filterDispatcher;
    }

    @Override
    public void startUsingConfiguredFilters() {
        resetRootFilter();
        startObservation();
    }

    protected void resetRootFilter() {
        synchronized (resetLock) {

            MgnlFilter newFilter;
            try {
                newFilter = createRootFilter();
                initRootFilter(newFilter, filterConfig);
            } catch (ServletException e) {
                log.error("Error initializing filters", e);
                return;
            }

            final MgnlFilter oldFilter = filterDispatcher.replaceTargetFilter(newFilter);

            // This is executed asynchronously in another thread so we don't risk causing dead lock, see SafeDestroyMgnlFilterWrapper
            doInSystemContextAsync("FilterChainDisposerThread", new MgnlContext.VoidOp() {
                @Override
                public void doExec() {
                    destroyRootFilter(oldFilter);
                }
            }, true);
        }
    }

    protected MgnlFilter createRootFilter() throws ServletException {
        if (isSystemUIMode()) {
            return createSystemUIFilter();
        }
        return createConfiguredFilters();
    }

    protected void initRootFilter(MgnlFilter rootFilter, FilterConfig filterConfig) throws ServletException {
        log.info("Initializing filters");
        rootFilter.init(filterConfig);

        if (log.isDebugEnabled()) {
            printFilters(rootFilter);
        }
    }

    protected void destroyRootFilter(MgnlFilter rootFilter) {
        if (rootFilter != null) {
            rootFilter.destroy();
        }
    }

    private MgnlFilter createConfiguredFilters() throws ServletException {
        try {
            final HierarchyManager hm = systemContext.getHierarchyManager(RepositoryConstants.CONFIG);
            final Content node = hm.getContent(SERVER_FILTERS);
            MgnlFilter filter = (MgnlFilter) nodeToBean.toBean(node.getJCRNode(), MgnlFilter.class);
            if (filter == null) {
                throw new ServletException("Unable to create filter objects");
            }
            return filter;
        } catch (PathNotFoundException e) {
            throw new ServletException("No filters configured at " + SERVER_FILTERS);
        } catch (RepositoryException e) {
            throw new ServletException("Can't read filter definitions", e);
        } catch (Node2BeanException e) {
            throw new ServletException("Can't create filter objects", e);
        }
    }

    /**
     * Initializes the required filter(s) if we need to go through
     * SystemUI initialization screens.
     */
    protected MgnlFilter createSystemUIFilter() {
        final CompositeFilter systemUIFilter = new CompositeFilter();
        final ServletDispatchingFilter classpathSpoolFilter = new ServletDispatchingFilter();
        classpathSpoolFilter.setName("resources");
        classpathSpoolFilter.setServletName("ClasspathSpool Servlet");
        classpathSpoolFilter.setServletClass(ClasspathSpool.class.getName());
        classpathSpoolFilter.addMapping("/.resources/*");
        classpathSpoolFilter.addMapping("/favicon.ico");
        classpathSpoolFilter.setParameters(Collections.emptyMap());
        classpathSpoolFilter.setEnabled(true);
        systemUIFilter.addFilter(classpathSpoolFilter);

        final InstallFilter installFilter = new InstallFilter(moduleManager, this);
        installFilter.setName("install");
        systemUIFilter.addFilter(installFilter);
        return systemUIFilter;
    }

    /**
     * Checks if Magnolia is ready to operate or if we need to go through
     * SystemUI initialization screens.
     */
    protected boolean isSystemUIMode() {
        return moduleManager.getStatus().needsUpdateOrInstall();
    }

    protected void startObservation() {
        ObservationUtil.registerDeferredChangeListener(RepositoryConstants.CONFIG, SERVER_FILTERS,
                filtersEventListener, 1000, 5000);
    }

    private void printFilters(MgnlFilter rootFilter) {
        log.debug("Here is the root filter as configured:");
        printFilter(0, rootFilter);
    }

    private void printFilter(int indentation, MgnlFilter filter) {
        log.debug("{}{} ({})",
                new Object[] { StringUtils.repeat(" ", indentation), filter.getName(), filter.toString() });
        if (filter instanceof CompositeFilter) {
            for (MgnlFilter nestedFilter : ((CompositeFilter) filter).getFilters()) {
                printFilter(indentation + 2, nestedFilter);
            }
        }
    }

    private <T, E extends Throwable> void doInSystemContextAsync(final String threadName,
            final MgnlContext.Op<T, E> op, final boolean releaseAfterExecution) {
        new Thread() {
            {
                setName(threadName);
            }

            @Override
            public void run() {
                try {
                    MgnlContext.doInSystemContext(op, releaseAfterExecution);
                } catch (Throwable e) {
                    log.error("Exception caught when executing asynchronous operation: " + e.getMessage(), e);
                }
            }
        }.start();
    }
}