Java tutorial
/******************************************************************************* * Copyright (c) 2008, 2010 VMware Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * VMware Inc. - initial contribution *******************************************************************************/ package net.solarnetwork.web.gemini; import java.io.IOException; import java.util.Map; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext; import org.eclipse.gemini.blueprint.context.support.OsgiBundleXmlApplicationContext; import org.eclipse.gemini.blueprint.extender.OsgiBeanFactoryPostProcessor; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.io.Resource; import org.springframework.ui.context.Theme; import org.springframework.ui.context.ThemeSource; import org.springframework.ui.context.support.UiApplicationContextUtils; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.context.ConfigurableWebApplicationContext; import org.springframework.web.context.ServletConfigAware; import org.springframework.web.context.ServletContextAware; import org.springframework.web.context.support.AbstractRefreshableWebApplicationContext; import org.springframework.web.context.support.ServletContextAwareProcessor; import org.springframework.web.context.support.ServletContextResourcePatternResolver; import org.springframework.web.context.support.StandardServletEnvironment; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.context.support.XmlWebApplicationContext; /** * <code>ServerOsgiBundleXmlWebApplicationContext</code> is a custom extension * of {@link OsgiBundleXmlApplicationContext} which provides support for * application contexts backed by an OSGi {@link Bundle bundle} in Spring MVC * based web applications by implementing * {@link ConfigurableWebApplicationContext}. * <p /> * * Since Java does not support multiple inheritance, the implementation details * specific to <code>ConfigurableWebApplicationContext</code> have been copied * directly from {@link XmlWebApplicationContext} and * {@link AbstractRefreshableWebApplicationContext}. * <p /> * * <strong>Concurrent Semantics</strong><br /> * * This class is not thread-safe. * */ public class ServerOsgiBundleXmlWebApplicationContext extends OsgiBundleXmlApplicationContext implements ConfigurableWebApplicationContext, ThemeSource { private final Logger logger = LoggerFactory.getLogger(this.getClass()); /** * {@link ServletContext} attribute name for the {@link BundleContext} to be * used to back this * {@link org.eclipse.gemini.blueprint.context.ConfigurableOsgiBundleApplicationContext * ConfigurableOsgiBundleApplicationContext}. */ public static final String BUNDLE_CONTEXT_ATTRIBUTE = "osgi-bundlecontext"; /** * service entry used for storing the namespace associated with this context */ private static final String APPLICATION_CONTEXT_SERVICE_NAMESPACE_PROPERTY = "org.springframework.web.context.namespace"; /** Suffix for WebApplicationContext namespaces. */ private static final String DEFAULT_NAMESPACE_SUFFIX = "-servlet"; private static final String PREFIX_DELIMITER = ":"; /** Servlet context that this context runs in */ private ServletContext servletContext; /** ResourcePatternResolver for the associated ServletContext. */ private ServletContextResourcePatternResolver servletContextResourcePatternResolver; /** Servlet config that this context runs in, if any */ private ServletConfig servletConfig; /** Namespace of this context, or <code>null</code> if root */ private String namespace; /** the ThemeSource for this ApplicationContext */ private ThemeSource themeSource; /** * Creates a <code>ServerOsgiBundleXmlWebApplicationContext</code> with no * parent. */ public ServerOsgiBundleXmlWebApplicationContext() { super(); setDisplayName("Root ServerOsgiBundleXmlWebApplicationContext"); } /** * Creates a <code>ServerOsgiBundleXmlWebApplicationContext</code> with the * supplied config locations. * * @param configLocations * the config locations. */ public ServerOsgiBundleXmlWebApplicationContext(String[] configLocations) { super(configLocations); setDisplayName("Root ServerOsgiBundleXmlWebApplicationContext"); logger.debug("Creating an ServerOsgiBundleXmlWebApplicationContext with locations [{}].", ObjectUtils.nullSafeToString(configLocations)); } /** * Creates a <code>ServerOsgiBundleXmlWebApplicationContext</code> with the * supplied parent. * * @param parent * the parent {@link ApplicationContext}. */ public ServerOsgiBundleXmlWebApplicationContext(ApplicationContext parent) { super(parent); setDisplayName("Root ServerOsgiBundleXmlWebApplicationContext"); logger.debug("Creating an ServerOsgiBundleXmlWebApplicationContext with parent [{}].", parent); } /** * Creates a <code>ServerOsgiBundleXmlWebApplicationContext</code> with the * supplied parent and config locations. * * @param configLocations * the config locations. * @param parent * the parent {@link ApplicationContext}. */ public ServerOsgiBundleXmlWebApplicationContext(String[] configLocations, ApplicationContext parent) { super(configLocations, parent); setDisplayName("Root ServerOsgiBundleXmlWebApplicationContext"); logger.debug("Creating an ServerOsgiBundleXmlWebApplicationContext with locations [{}] and parent [{}].", ObjectUtils.nullSafeToString(configLocations), parent); } /** * Determines if the supplied <code>location</code> does not have a prefix. */ protected static boolean hasNoPrefix(String location) { return location == null || location.indexOf(PREFIX_DELIMITER) < 1; } /** * {@inheritDoc} */ @Override public void setServletContext(final ServletContext servletContext) { this.servletContext = servletContext; this.servletContextResourcePatternResolver = new ServletContextResourcePatternResolver(servletContext); // If the BundleContext has not yet been set, attempt to retrieve it from the ServletContext or the parent // ApplicationContext. if (getBundleContext() == null) { getBundleContext(); } } /** * {@inheritDoc} */ @Override public BundleContext getBundleContext() { BundleContext bundleContext = super.getBundleContext(); if (bundleContext == null) { // Attempt to locate the BundleContext in the ServletContext if (this.servletContext != null) { Object bundleContextFromServletContext = this.servletContext.getAttribute(BUNDLE_CONTEXT_ATTRIBUTE); if (bundleContextFromServletContext != null) { Assert.isInstanceOf(BundleContext.class, bundleContextFromServletContext); this.logger.debug("Using the BundleContext stored in the ServletContext as '{}'.", BUNDLE_CONTEXT_ATTRIBUTE); bundleContext = (BundleContext) bundleContextFromServletContext; setBundleContext(bundleContext); } } // If still not set, fall back to the parent if (bundleContext == null) { ApplicationContext parent = getParent(); if (parent instanceof ConfigurableOsgiBundleApplicationContext) { this.logger.debug("Using the parent ApplicationContext's BundleContext"); bundleContext = ((ConfigurableOsgiBundleApplicationContext) parent).getBundleContext(); setBundleContext(bundleContext); } } } return bundleContext; } /** * {@inheritDoc} */ @Override public ServletContext getServletContext() { return this.servletContext; } /** * {@inheritDoc} */ @Override public void setServletConfig(ServletConfig servletConfig) { this.servletConfig = servletConfig; if (servletConfig != null) { if (getServletContext() == null) { setServletContext(servletConfig.getServletContext()); } if (getNamespace() == null) { setNamespace(servletConfig.getServletName() + DEFAULT_NAMESPACE_SUFFIX); } } } /** * {@inheritDoc} */ @Override public ServletConfig getServletConfig() { return this.servletConfig; } /** * Set the config locations for this application context in init-param * style, i.e. with distinct locations separated by commas, semicolons or * whitespace. * <p> * If not set, the implementation may use a default as appropriate. */ @Override public void setConfigLocation(String location) { setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS)); } /** * The default location for the root context is * "/WEB-INF/applicationContext.xml", and "/WEB-INF/test-servlet.xml" for a * context with the namespace "test-servlet" (like for a DispatcherServlet * instance with the servlet-name "test"). */ @Override protected String[] getDefaultConfigLocations() { String ns = getNamespace(); if (ns != null) { return new String[] { XmlWebApplicationContext.DEFAULT_CONFIG_LOCATION_PREFIX + ns + XmlWebApplicationContext.DEFAULT_CONFIG_LOCATION_SUFFIX }; } else { return new String[] { XmlWebApplicationContext.DEFAULT_CONFIG_LOCATION }; } } /** * {@inheritDoc} */ @Override public void setNamespace(String namespace) { this.namespace = namespace; if (namespace != null) { setDisplayName("ServerOsgiBundleXmlWebApplicationContext for namespace '" + namespace + "'"); } } /** * {@inheritDoc} */ @Override public String getNamespace() { return this.namespace; } /** * Register request/session scopes, a {@link ServletContextAwareProcessor}, * etc. * * @see WebApplicationContextUtils#registerWebApplicationScopes(ConfigurableListableBeanFactory) */ @Override protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { super.postProcessBeanFactory(beanFactory); // Drive the kernel's bean factory post processors. BundleContext bundleContext = getBundleContext(); if (bundleContext != null) { ServiceReference<OsgiBeanFactoryPostProcessor> sr = bundleContext .getServiceReference(OsgiBeanFactoryPostProcessor.class); if (sr != null) { OsgiBeanFactoryPostProcessor kernelPostProcessor = bundleContext.getService(sr); try { kernelPostProcessor.postProcessBeanFactory(bundleContext, beanFactory); } catch (Exception e) { throw new ApplicationContextException("Kernel bean factory post processor failed", e); } finally { bundleContext.ungetService(sr); } } } beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(getServletContext(), getServletConfig())); beanFactory.ignoreDependencyInterface(ServletContextAware.class); beanFactory.ignoreDependencyInterface(ServletConfigAware.class); beanFactory.registerResolvableDependency(ServletContext.class, getServletContext()); beanFactory.registerResolvableDependency(ServletConfig.class, getServletConfig()); WebApplicationContextUtils.registerWebApplicationScopes(beanFactory); } /** * {@inheritDoc} * * Additionally, this implementation publishes the context namespace under * the <code>org.springframework.web.context.namespace</code> property. */ @SuppressWarnings({ "unchecked", "rawtypes" }) @Override protected void customizeApplicationContextServiceProperties(Map serviceProperties) { super.customizeApplicationContextServiceProperties(serviceProperties); String ns = getNamespace(); if (ns != null) { serviceProperties.put(APPLICATION_CONTEXT_SERVICE_NAMESPACE_PROPERTY, ns); } } /** * Returns a * {@link org.springframework.web.context.support.ServletContextResource * ServletContextResource} if the supplied <code>location</code> does not * have a prefix and otherwise delegates to the parent implementation for * standard Spring DM resource loading semantics. * <p/> * This override is necessary to return a suitable {@link Resource} type for * flow-relative views. See DMS-2310. */ @Override public Resource getResource(String location) { if (hasNoPrefix(location)) { return this.servletContextResourcePatternResolver.getResource(location); } return super.getResource(location); } /** * Returns an array of * {@link org.springframework.web.context.support.ServletContextResource * ServletContextResource}s if the supplied <code>locationPattern</code> * does not have a prefix and otherwise delegates to the parent * implementation for standard Spring DM resource loading semantics. * <p/> * This override is necessary to return a suitable {@link Resource} type for * flow-relative views. See DMS-2310. */ @Override public Resource[] getResources(String locationPattern) throws IOException { if (hasNoPrefix(locationPattern)) { return this.servletContextResourcePatternResolver.getResources(locationPattern); } return super.getResources(locationPattern); } /** * Initialize the theme capability. */ @Override protected void onRefresh() { this.themeSource = UiApplicationContextUtils.initThemeSource(this); } /** * {@inheritDoc} */ @Override public Theme getTheme(String themeName) { return this.themeSource.getTheme(themeName); } /** * {@inheritDoc} */ @Override protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); } }