ch.entwine.weblounge.kernel.publisher.ResourcePublishingService.java Source code

Java tutorial

Introduction

Here is the source code for ch.entwine.weblounge.kernel.publisher.ResourcePublishingService.java

Source

/*
 *  Weblounge: Web Content Management System
 *  Copyright (c) 2003 - 2011 The Weblounge Team
 *  http://entwinemedia.com/weblounge
 *
 *  This program is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public License
 *  as published by the Free Software Foundation; either version 2
 *  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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program; if not, write to the Free Software Foundation
 *  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

package ch.entwine.weblounge.kernel.publisher;

import static ch.entwine.weblounge.dispatcher.SharedHttpContext.ALIAS;

import ch.entwine.weblounge.dispatcher.SharedHttpContext;

import org.apache.commons.lang.StringUtils;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleListener;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Dictionary;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.servlet.Servlet;

/**
 * This service will publish static resources in bundles that expose the
 * following headers in their manifest:
 * <ul>
 * <li><code>Http-Alias</code> path to mount the resources to</li>
 * <li><code>Http-Resource</code> the resources to expose</li>
 * <li><code>Http-Welcome</code> the welcome file</li>
 * </ul>
 */
public class ResourcePublishingService implements BundleListener {

    /** Logging facility */
    private static final Logger logger = LoggerFactory.getLogger(ResourcePublishingService.class);

    /** The bundle header identifying the alias to mount the static resource to */
    public static final String HTTP_CONTEXT = "Http-Context";

    /** The bundle header identifying the path to the static resource */
    public static final String HTTP_RESOURCE = "Http-Resource";

    /** The bundle header identifying the welcome file */
    public static final String HTTP_WELCOME = "Http-Welcome";

    /** Mapping of registered endpoints */
    protected Map<String, ServiceRegistration> resourceRegistrations = new HashMap<String, ServiceRegistration>();

    /**
     * OSGi callback on component activation.
     * 
     * @param ctx
     *          the component context
     */
    protected void activate(ComponentContext ctx) {
        BundleContext bundleCtx = ctx.getBundleContext();

        // Process bundles that have already been started
        for (Bundle bundle : bundleCtx.getBundles()) {
            if (bundle.getState() == Bundle.ACTIVE)
                registerResources(bundle);
        }

        bundleCtx.addBundleListener(this);
    }

    /**
     * OSGi callback on component inactivation.
     * 
     * @param ctx
     *          the component context
     */
    protected void deactivate(ComponentContext ctx) {
        ctx.getBundleContext().removeBundleListener(this);

        synchronized (resourceRegistrations) {
            for (Map.Entry<String, ServiceRegistration> entry : resourceRegistrations.entrySet()) {
                String bundleSymbolicName = entry.getKey();
                ServiceRegistration servlet = entry.getValue();
                logger.debug("Unpublishing resources at {}", bundleSymbolicName);
                try {
                    servlet.unregister();
                } catch (IllegalStateException e) {
                    // Never mind, the service has been unregistered already
                } catch (Throwable t) {
                    logger.error("Unregistering resource servlet failed: {}", t.getMessage());
                }
            }
            resourceRegistrations.clear();
        }
    }

    /**
     * Registers any static resources that are declared in the bundle's manifest
     * as a servlet.
     * 
     * @param bundle
     *          the active bundle
     */
    public void registerResources(Bundle bundle) {

        String resourcePath = (String) bundle.getHeaders().get(HTTP_RESOURCE);
        String contextPath = (String) bundle.getHeaders().get(HTTP_CONTEXT);
        String welcomeFile = (String) bundle.getHeaders().get(HTTP_WELCOME);

        // Are there any relevant manifest headers?
        if (StringUtils.isBlank(resourcePath) || StringUtils.isBlank(contextPath)) {
            logger.debug("No resource manifest headers found in bundle {}", bundle.getSymbolicName());
            return;
        }

        BundleContext bundleCtx = bundle.getBundleContext();

        logger.info("Publishing resources from bundle://{} at {}", bundle.getSymbolicName(), contextPath);

        // Create and register the resource servlet
        try {
            Servlet servlet = new ResourcesServlet(bundle, resourcePath, welcomeFile);
            Dictionary<String, String> servletRegistrationProperties = new Hashtable<String, String>();
            servletRegistrationProperties.put(ALIAS, contextPath);
            servletRegistrationProperties.put(SharedHttpContext.SERVLET_NAME, bundle.getSymbolicName() + "-static");
            ServiceRegistration servletRegistration = bundleCtx.registerService(Servlet.class.getName(), servlet,
                    servletRegistrationProperties);
            resourceRegistrations.put(bundle.getSymbolicName(), servletRegistration);
        } catch (Throwable t) {
            logger.error("Error publishing resources service at " + contextPath, t);
        }

    }

    /**
     * Removes any resource registrations associated with this bundle.
     * 
     * @param bundle
     *          the stopped bundle
     */
    public void unregisterResources(Bundle bundle) {
        String contextPath = (String) bundle.getHeaders().get(HTTP_CONTEXT);
        if (StringUtils.isBlank(contextPath)) {
            logger.debug("Bundle '{}' does not expose static resources", bundle.getSymbolicName());
            return;
        }

        // The services were registered using the bundle's context. Since that
        // bundle has been stopped now, the service has been unregistered by the
        // OSGi service registry already
        synchronized (resourceRegistrations) {
            resourceRegistrations.remove(bundle.getSymbolicName());
            logger.info("Unpublishing resources at {}", contextPath);
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
     */
    public void bundleChanged(BundleEvent event) {
        switch (event.getType()) {
        case BundleEvent.STARTED:
            registerResources(event.getBundle());
            break;
        case BundleEvent.STOPPED:
            unregisterResources(event.getBundle());
            break;
        default:
            break;
        }
    }

}