Java tutorial
/* * 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; } } }