/*
* Copyright 2005 Joe Walker
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.directwebremoting.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.xml.parsers.ParserConfigurationException;
import org.directwebremoting.Container;
import org.directwebremoting.HubFactory;
import org.directwebremoting.ServerContext;
import org.directwebremoting.ServerContextFactory;
import org.directwebremoting.WebContextFactory;
import org.directwebremoting.WebContextFactory.WebContextBuilder;
import org.directwebremoting.annotations.AnnotationsConfigurator;
import org.directwebremoting.event.ScriptSessionListener;
import org.directwebremoting.extend.AccessControl;
import org.directwebremoting.extend.AjaxFilterManager;
import org.directwebremoting.extend.CallbackHelperFactory;
import org.directwebremoting.extend.Configurator;
import org.directwebremoting.extend.ContainerAbstraction;
import org.directwebremoting.extend.ContainerConfigurationException;
import org.directwebremoting.extend.ConverterManager;
import org.directwebremoting.extend.Creator;
import org.directwebremoting.extend.CreatorManager;
import org.directwebremoting.extend.DwrConstants;
import org.directwebremoting.extend.Handler;
import org.directwebremoting.extend.ModuleManager;
import org.directwebremoting.extend.ScriptSessionManager;
import org.directwebremoting.extend.ServerLoadMonitor;
import org.directwebremoting.extend.TaskDispatcherFactory;
import org.directwebremoting.json.parse.JsonParserFactory;
import org.directwebremoting.json.serialize.JsonSerializerFactory;
import org.directwebremoting.servlet.PathConstants;
import org.directwebremoting.servlet.UrlProcessor;
import org.directwebremoting.util.FakeServletConfig;
import org.directwebremoting.util.FakeServletContext;
import org.directwebremoting.util.LocalUtil;
import org.directwebremoting.util.Loggers;
import org.directwebremoting.util.VersionUtil;
import org.xml.sax.SAXException;
/**
* Some utilities to help get DWR up and running
* @author Joe Walker [joe at getahead dot ltd dot uk]
*/
public class StartupUtil
{
/**
* Init parameter: Set a dwr.xml config file.
* This is only a prefix since we might have more than 1 config file.
*/
public static final String INIT_CONFIG = "config";
/**
* Init parameter: Skip reading the default config file if none are specified.
*/
public static final String INIT_SKIP_DEFAULT = "skipDefaultConfig";
/**
* Init parameter: If we are doing Servlet.log logging, to what level?
*/
public static final String INIT_LOGLEVEL = "logLevel";
/**
* Init parameter: If you wish to use a custom configurator, place its
* class name here
*/
public static final String INIT_CUSTOM_CONFIGURATOR = "customConfigurator";
/**
* The name under which we publish all {@link Container}s.
*/
public static final String ATTRIBUTE_CONTAINER_LIST = "org.directwebremoting.ContainerList";
/**
* A way to setup DWR outside of any Containers.
* This method can also serve as a template for in container code wanting
* to get DWR setup. Callers of this method should clean up after themselves
* by calling {@link #outOfContainerDestroy(Container)}
* @return A new initialized container.
* @throws ContainerConfigurationException If we can't use a bean
*/
public static Container outOfContainerInit() throws ContainerConfigurationException
{
try
{
ServletConfig servletConfig = new FakeServletConfig("test", new FakeServletContext());
logStartup("DWR:OutOfContainer", servletConfig);
Container container = createAndSetupDefaultContainer(servletConfig);
configureContainerFully(container, servletConfig);
return container;
}
catch (ContainerConfigurationException ex)
{
throw ex;
}
catch (Exception ex)
{
throw new ContainerConfigurationException(ex);
}
}
/**
* Clean up the current thread when {@link #outOfContainerInit()} has been
* called.
* @param container The container created by {@link #outOfContainerInit()}.
*/
public static void outOfContainerDestroy(Container container)
{
WebContextBuilder webContextBuilder = container.getBean(WebContextBuilder.class);
if (webContextBuilder != null)
{
webContextBuilder.disengageThread();
}
}
/**
* Some logging so we have a good clue what we are working with.
* @param name The servlet name (so we can distinguish implementations)
* @param config The servlet config
*/
public static void logStartup(String name, ServletConfig config)
{
ServletContext servletContext = config.getServletContext();
// SERVLET24: Use getContextPath directly in 2.5
String contextPath = LocalUtil.getProperty(servletContext, "ContextPath", String.class);
contextPath = contextPath == null ? "" : " at " + contextPath;
Loggers.STARTUP.info("Starting: " + name + " v" + VersionUtil.getLabel() + " on " + servletContext.getServerInfo() + " / JDK " + System.getProperty("java.version") + " from " + System.getProperty("java.vendor") + contextPath);
}
/**
* A combination of {@link #createDefaultContainer(ServletConfig)} and
* {@link #setupDefaultContainer(DefaultContainer, ServletConfig)}.
* @param servletConfig The source of init parameters
* @return A setup implementation of DefaultContainer
* @throws ContainerConfigurationException If the specified class could not be found or instantiated
*/
public static Container createAndSetupDefaultContainer(ServletConfig servletConfig) throws ContainerConfigurationException
{
Container container;
try
{
String typeName = servletConfig.getInitParameter(LocalUtil.originalDwrClassName(Container.class.getName()));
if (typeName == null)
{
container = new DefaultContainer();
}
else
{
Loggers.STARTUP.debug("Using alternate Container implementation: " + typeName);
Class<?> type = LocalUtil.classForName(typeName);
container = (Container) type.newInstance();
}
if (container instanceof DefaultContainer)
{
DefaultContainer defaultContainer = (DefaultContainer) container;
setupDefaultContainer(defaultContainer, servletConfig);
}
}
catch (Exception ex)
{
throw new ContainerConfigurationException(ex);
}
return container;
}
/**
* Create a {@link DefaultContainer}, allowing users to upgrade to a child
* of DefaultContainer using an {@link ServletConfig} init parameter of
* <code>org.directwebremoting.Container</code>. Note that while the
* parameter name is the classname of {@link Container}, currently the only
* this can only be used to create children that inherit from
* {@link DefaultContainer}. This restriction may be relaxed in the future.
* Unlike {@link #setupDefaultContainer(DefaultContainer, ServletConfig)},
* this method does not call any setup methods.
* @param servletConfig The source of init parameters
* @return An un'setup' implementation of DefaultContainer
* @throws ContainerConfigurationException If the specified class could not be found
* @see ServletConfig#getInitParameter(String)
*/
public static DefaultContainer createDefaultContainer(ServletConfig servletConfig) throws ContainerConfigurationException
{
try
{
String typeName = servletConfig.getInitParameter(LocalUtil.originalDwrClassName(Container.class.getName()));
if (typeName == null)
{
return new DefaultContainer();
}
Loggers.STARTUP.debug("Using alternate Container implementation: " + typeName);
Class<?> type = LocalUtil.classForName(typeName);
return (DefaultContainer) type.newInstance();
}
catch (Exception ex)
{
throw new ContainerConfigurationException(ex);
}
}
/**
* Setup a {@link DefaultContainer}.
* Using {@link #createDefaultContainer(ServletConfig)} followed by
* {@link #setupFromServletConfig(DefaultContainer, ServletConfig)} before
* calling {@link DefaultContainer#setupFinished()}.
* @param container The container to configure
* @param servletConfig The source of init parameters
* @throws ContainerConfigurationException If we can't use a bean
*/
public static void setupDefaultContainer(DefaultContainer container, ServletConfig servletConfig) throws ContainerConfigurationException
{
Loggers.STARTUP.debug("Setup: Getting parameters from defaults.properties:");
setupDefaults(container);
// Add the ServletConfig and ServletContext to the container so they can
// be injected into contained beans
Loggers.STARTUP.debug("Setup: Getting parameters from environment:");
container.addBean(Container.class, container);
container.addBean(ServletConfig.class, servletConfig);
container.addBean(ServletContext.class, servletConfig.getServletContext());
Loggers.STARTUP.debug("Setup: Getting parameters from ServletConfig:");
setupFromServletConfig(container, servletConfig);
Loggers.STARTUP.debug("Setup: Applying long versions of shortcut parameters:");
applyParameterShortcuts(container);
Loggers.STARTUP.debug("Setup: Resolving multiple implementations:");
resolveMultipleImplementations(container, servletConfig);
Loggers.STARTUP.debug("Setup: Autowire beans");
container.setupFinished();
Loggers.STARTUP.debug("Setup: Resolving listener implementations:");
resolveListenerImplementations(container, servletConfig);
Loggers.STARTUP.debug("Setup: Initializing Factories:");
ServerContext serverContext = ServerContextFactory.attach(container);
WebContextFactory.attach(container);
HubFactory.attach(container);
JsonParserFactory.attach(container);
JsonSerializerFactory.attach(container);
CallbackHelperFactory.attach(container);
TaskDispatcherFactory.attach(container);
// Make some changes to the ServletContext so {@link DwrWebContextFilter}
// can find the Container etc.
WebContextBuilder webContextBuilder = container.getBean(WebContextBuilder.class);
ServletContext servletContext = servletConfig.getServletContext();
servletContext.setAttribute(Container.class.getName(), container);
servletContext.setAttribute(WebContextBuilder.class.getName(), webContextBuilder);
servletContext.setAttribute(ServletConfig.class.getName(), servletConfig);
publishContainer(container, serverContext, servletConfig);
}
/**
* Some parameters might be shortcuts for one or more other parameters.
* For example 'interactivity. This method resolves those shortcuts by
* adding new values into the container.
*/
private static void applyParameterShortcuts(DefaultContainer container)
{
Object bean = container.getBean("interactivity");
if (bean == null)
{
return;
}
if (bean instanceof String)
{
String level = (String) bean;
if ("stateless".equals(level))
{
container.addImplementation(ScriptSessionManager.class, TransientScriptSessionManager.class);
}
else if ("passiveReverseAjax".equals(level))
{
// The default - do nothing
}
else if ("activeReverseAjax".equals(level))
{
container.addParameter("activeReverseAjax", "true");
}
else
{
Loggers.STARTUP.error("Illegal value for 'interactivity' parameter of '" + level + "'. Valid values are [stateless|passiveReverseAjax|activeReverseAjax]. Ignoring.");
}
}
else
{
Loggers.STARTUP.error("Found non-string value for 'interactivity' parameter. Ignoring.");
}
}
/**
* We need to decide which {@link ContainerAbstraction} should be the
* default for this {@link Container}, also we should prepare the default
* {@link ServerLoadMonitor}.
* @param container The container to configure
* @param servletConfig Information about the environment
* @throws ContainerConfigurationException If we can't use a bean
*/
@SuppressWarnings("unchecked")
public static void resolveMultipleImplementations(DefaultContainer container, ServletConfig servletConfig) throws ContainerConfigurationException
{
// Use DwrConstants to avoid rename if DWR repackaged (shaded)
try
{
resolveMultipleImplementation(container, LocalUtil.originalDwrClassName("org.directwebremoting.dwrp.FileUpload"));
}
catch(Exception fue)
{
Loggers.STARTUP.debug("A FileUpload implementation is not available. Details: " + fue, fue);
}
try
{
resolveMultipleImplementation(container, LocalUtil.originalDwrClassName("org.directwebremoting.extend.Compressor"));
} catch(Exception ce)
{
Loggers.STARTUP.debug("A Compressor implemenation is not available. Details: " + ce, ce);
}
String abstractionImplNames = container.getParameter(LocalUtil.originalDwrClassName(ContainerAbstraction.class.getName()));
Loggers.STARTUP.debug("- Selecting a " + ContainerAbstraction.class.getSimpleName() + " from " + abstractionImplNames);
abstractionImplNames = abstractionImplNames.replace(',', ' ');
for (String abstractionImplName : abstractionImplNames.split(" "))
{
try
{
if (abstractionImplName.trim().length() == 0)
{
continue;
}
Class<ContainerAbstraction> abstractionImpl = (Class<ContainerAbstraction>) LocalUtil.classForName(abstractionImplName);
ContainerAbstraction abstraction = abstractionImpl.newInstance();
if (abstraction.isNativeEnvironment(servletConfig))
{
container.addImplementation(ContainerAbstraction.class, abstractionImpl);
String loadMonitorImplName = container.getParameter(LocalUtil.originalDwrClassName(ServerLoadMonitor.class.getName()));
if (loadMonitorImplName == null)
{
Class<? extends ServerLoadMonitor> loadMonitorImpl = abstraction.getServerLoadMonitorImplementation();
container.addImplementation(ServerLoadMonitor.class, loadMonitorImpl);
}
return;
}
}
catch (Exception ex)
{
Loggers.STARTUP.debug(" - Can't use : " + abstractionImplName + " to implement " + ContainerAbstraction.class.getName() + ". This is probably not an error unless you were expecting to use it. Reason: " + ex);
}
catch (NoClassDefFoundError ex)
{
Loggers.STARTUP.debug(" - Can't use : " + abstractionImplName + " to implement " + ContainerAbstraction.class.getName() + ". This is probably not an error unless you were expecting to use it. Reason: " + ex);
}
}
throw new ContainerConfigurationException("None of the configured ContainerAbstractions claims isNativeEnvironment=true. Implementations tested: " + abstractionImplNames);
}
/**
* Some interfaces have multiple options, and we pick the first that we
* can construct. The assumption is that multiple implementations are
* held as strings concatenated, separated with spaces.
* @param container The container which has a multiple implementation
* @param toResolveString The class name which needs disambiguating
*/
protected static void resolveMultipleImplementation(DefaultContainer container, String toResolveString)
{
Class<?> toResolve = null;
try
{
toResolve = LocalUtil.classForName(toResolveString);
}
catch (Exception ex)
{
Loggers.STARTUP.debug(toResolveString + " is not available. Details: " + ex);
}
String implNames = container.getParameter(toResolveString);
Loggers.STARTUP.debug("- Selecting a " + toResolveString + " from " + implNames);
implNames = implNames.replace(',', ' ');
for (String implName : implNames.split(" "))
{
if (implName.equals(""))
{
continue;
}
try
{
Class<?> impl = LocalUtil.classForName(implName);
if (!toResolve.isAssignableFrom(impl))
{
Loggers.STARTUP.error(" - Can't cast: " + impl.getName() + " to " + toResolve.getName());
}
impl.newInstance();
container.addParameter(LocalUtil.originalDwrClassName(toResolve.getName()), impl.getName());
return;
}
catch (Exception ex)
{
Loggers.STARTUP.debug(" - Can't use : " + implName + " to implement " + toResolve.getName() + ". This is probably not an error unless you were expecting to use it. Reason: " + ex);
}
catch (Throwable t)
{
Loggers.STARTUP.debug(" - Can't use : " + implName + " to implement " + toResolve.getName() + ". This is probably not an error unless you were expecting to use it. Reason: " + t);
}
}
}
/**
* We need to add all the {@link ScriptSessionListener}s to the
* {@link ScriptSessionManager}.
* @param container The container to configure
* @param servletConfig Information about the environment
* @throws ContainerConfigurationException If we can't use a bean
*/
public static void resolveListenerImplementations(DefaultContainer container, ServletConfig servletConfig) throws ContainerConfigurationException
{
ScriptSessionManager manager = container.getBean(ScriptSessionManager.class);
String implNames = container.getParameter(LocalUtil.originalDwrClassName(ScriptSessionListener.class.getName()));
if (implNames == null)
{
Loggers.STARTUP.debug("- No implementations of " + ScriptSessionListener.class.getSimpleName() + " to register");
return;
}
Loggers.STARTUP.debug("- Creating list of " + ScriptSessionListener.class.getSimpleName() + " from " + implNames);
implNames = implNames.replace(',', ' ');
for (String implName : implNames.split(" "))
{
if (implName.equals(""))
{
continue;
}
try
{
Class<?> impl = LocalUtil.classForName(implName);
if (!ScriptSessionListener.class.isAssignableFrom(impl))
{
Loggers.STARTUP.error(" - Can't cast: " + impl.getName() + " to " + ScriptSessionListener.class.getName());
}
else
{
@SuppressWarnings("unchecked")
Class<? extends ScriptSessionListener> i = (Class<? extends ScriptSessionListener>) impl;
ScriptSessionListener instance = i.newInstance();
manager.addScriptSessionListener(instance);
}
}
catch (Exception ex)
{
Loggers.STARTUP.error(" - Can't use : " + implName + " to implement " + ScriptSessionListener.class.getName() + ". Reason: " + ex);
}
catch (NoClassDefFoundError ex)
{
Loggers.STARTUP.error(" - Can't use : " + implName + " to implement " + ScriptSessionListener.class.getName() + ". Reason: " + ex);
}
}
}
/**
* Take a DefaultContainer and setup the default beans
* @param container The container to configure
* @throws ContainerConfigurationException If we can't use a bean
*/
public static void setupDefaults(DefaultContainer container) throws ContainerConfigurationException
{
try
{
InputStream in = LocalUtil.getInternalResourceAsStream(DwrConstants.SYSTEM_DEFAULT_PROPERTIES_PATH);
Properties defaults = new Properties();
defaults.load(in);
for (Map.Entry<?, ?> entry : defaults.entrySet())
{
String key = (String) entry.getKey();
String value = (String) entry.getValue();
container.addParameter(key, value);
}
}
catch (IOException ex)
{
throw new ContainerConfigurationException("Failed to load system defaults", ex);
}
}
/**
* Creates entries in the {@link Container} so 2 lookups are possible.
* <ul>
* <li>You can find a {@link Handler} for a URL. Used by {@link UrlProcessor}
* <li>You can inject (or lookup) the URL assigned to a {@link Handler}
* </ul>
* @param container The container to create the entries in
* @param url The URL of the new {@link Handler}
* @param handler The class of Handler
* @param propertyName The property name (for injection and lookup)
* @throws ContainerConfigurationException From {@link DefaultContainer#addParameter(String, Object)}
*/
public static void createPathMapping(DefaultContainer container, String url, Class<? extends Handler> handler, String propertyName) throws ContainerConfigurationException
{
container.addParameter(PathConstants.PATH_PREFIX + url, handler.getName());
if (propertyName != null)
{
container.addParameter(propertyName, url);
}
}
/**
* Creates entries in the {@link Container} so 1 lookup is possible.
* <ul>
* <li>You can find a {@link Handler} for a URL. Used by {@link UrlProcessor}
* </ul>
* @param container The container to create the entries in
* @param url The URL of the new {@link Handler}
* @param handler The class of Handler
* @throws ContainerConfigurationException From {@link DefaultContainer#addParameter(String, Object)}
*/
public static void createPathMapping(DefaultContainer container, String url, Class<? extends Handler> handler) throws ContainerConfigurationException
{
createPathMapping(container, url, handler, null);
}
/**
* Take a DefaultContainer and setup the default beans
* @param container The container to configure
* @param servletConfig The servlet configuration (null to ignore)
* @throws ContainerConfigurationException If we can't use a bean
*/
@SuppressWarnings("unchecked")
public static void setupFromServletConfig(DefaultContainer container, ServletConfig servletConfig) throws ContainerConfigurationException
{
Enumeration<String> en = servletConfig.getInitParameterNames();
while (en.hasMoreElements())
{
String name = en.nextElement();
String value = servletConfig.getInitParameter(name);
container.addParameter(name, value);
}
}
/**
* Configure using the system dwr.xml from within the JAR file.
* @param container The container to configure
* @throws ParserConfigurationException If the config file parse fails
* @throws IOException If the config file read fails
* @throws SAXException If the config file parse fails
*/
public static void configureFromSystemDwrXml(Container container) throws IOException, ParserConfigurationException, SAXException
{
DwrXmlConfigurator system = new DwrXmlConfigurator();
system.setClassResourceName(DwrConstants.SYSTEM_DWR_XML_PATH);
system.configure(container);
}
/**
* Configure using the users dwr.xml that sits next in WEB-INF
* @param container The container to configure
* @throws ParserConfigurationException If the config file parse fails
* @throws IOException If the config file read fails
* @throws SAXException If the config file parse fails
*/
public static void configureFromDefaultDwrXml(Container container, ServletConfig servletConfig) throws IOException, ParserConfigurationException, SAXException
{
DwrXmlConfigurator local = new DwrXmlConfigurator();
local.setServletResourceName(servletConfig.getServletContext(), DwrConstants.USER_DWR_XML_PATH);
local.configure(container);
}
/**
* Add configurators from init params to the end of the list of
* configurators.
* @param container The container to configure
* @param servletConfig The source of init parameters
* @return true if any Configurators were read
* @throws SAXException If the config file parse fails
* @throws ParserConfigurationException If the config file parse fails
* @throws IOException If the config file read fails
*/
@SuppressWarnings("unchecked")
public static boolean configureFromInitParams(Container container, ServletConfig servletConfig) throws IOException, ParserConfigurationException, SAXException
{
Enumeration<String> en = servletConfig.getInitParameterNames();
boolean foundConfig = false;
while (en.hasMoreElements())
{
String name = en.nextElement();
String value = servletConfig.getInitParameter(name);
// if the init param starts with "config" then try to load it
if (name.startsWith(INIT_CONFIG))
{
foundConfig = true;
StringTokenizer st = new StringTokenizer(value, "\n,");
while (st.hasMoreTokens())
{
String fileName = st.nextToken().trim();
DwrXmlConfigurator local = new DwrXmlConfigurator();
local.setServletResourceName(servletConfig.getServletContext(), fileName);
local.configure(container);
}
}
else if (name.equals(INIT_CUSTOM_CONFIGURATOR))
{
foundConfig = true;
try
{
Configurator configurator = LocalUtil.classNewInstance(INIT_CUSTOM_CONFIGURATOR, value, Configurator.class);
configurator.configure(container);
Loggers.STARTUP.debug("Loaded config from: " + value);
}
catch (Exception ex)
{
Loggers.STARTUP.error("Failed to start custom configurator", ex);
}
}
}
return foundConfig;
}
/**
* Annotations must not break 1.3, so we use reflection to create an
* <code>org.directwebremoting.annotations.AnnotationsConfigurator</code>
* and the catch all sorts of random exceptions for the benefit of
* Websphere.
* @param container The container to configure
* @return true if the configuration worked.
*/
public static boolean configureFromAnnotations(Container container)
{
Object data = container.getBean("classes");
if (null != data)
{
Configurator configurator = new AnnotationsConfigurator();
configurator.configure(container);
Loggers.STARTUP.debug("Java5 AnnotationsConfigurator enabled");
return true;
}
return false;
}
/**
* Allow all the configurators to have a go at the container in turn
* @param container The container to configure
* @param configurators A list of configurators to run against the container
*/
public static void configure(Container container, List<Configurator> configurators)
{
// Allow all the configurators to have a go
for (Configurator configurator : configurators)
{
Loggers.STARTUP.debug("Adding config from " + configurator);
configurator.configure(container);
}
}
/**
* Run all the default configuration options on a Container
* @param container The container to configure
* @param servletConfig The source of init parameters
* @throws SAXException If the config file parse fails
* @throws ParserConfigurationException If the config file parse fails
* @throws IOException If the config file read fails
*/
public static void configureContainerFully(Container container, ServletConfig servletConfig) throws IOException, ParserConfigurationException, SAXException
{
configureFromSystemDwrXml(container);
boolean foundConfig = configureFromInitParams(container, servletConfig);
// The default dwr.xml file that sits by web.xml
boolean skip = Boolean.valueOf(servletConfig.getInitParameter(INIT_SKIP_DEFAULT));
IOException delayedIOException = null;
if (!foundConfig && !skip)
{
try
{
configureFromDefaultDwrXml(container, servletConfig);
}
catch (IOException ex)
{
// This is fatal unless we are on JDK5+ AND using annotations
delayedIOException = ex;
}
}
if (!configureFromAnnotations(container))
{
Loggers.STARTUP.debug("Java5 AnnotationsConfigurator disabled");
if (delayedIOException != null)
{
throw delayedIOException;
}
}
}
/**
* If helps some situations if people can get at the container by looking
* in the servlet context, under some name.
* The name is specified in an initParameter.
* @param container The container to publish
* @param servletConfig Source of initParams to dictate publishing and contexts to publish to
*/
@SuppressWarnings("unchecked")
private static void publishContainer(Container container, ServerContext serverContext, ServletConfig servletConfig)
{
ServletContext servletContext = servletConfig.getServletContext();
// Push the container into a list that holds all the known containers
List<Container> containers = (List<Container>) servletContext.getAttribute(ATTRIBUTE_CONTAINER_LIST);
if (containers == null)
{
containers = new ArrayList<Container>();
}
containers.add(container);
servletContext.setAttribute(ATTRIBUTE_CONTAINER_LIST, containers);
// Attempt to set the singleton ServerContext, unsetting for all if
// there is already one
synchronized (contextMap)
{
switch (foundContexts)
{
case 0:
// No-one has been here before - set us as the default
singletonServerContext = serverContext;
break;
case 1:
// We're second - remove the previous guy from being default
singletonServerContext = null;
Loggers.STARTUP.debug("Multiple instances of DWR detected.");
break;
default:
// We're third or more - leave it that there is no default
break;
}
// Whatever, record the ServerContext against our servlet name
String name = servletConfig.getServletName();
contextMap.put(name, serverContext);
Loggers.STARTUP.debug("Adding to contextMap, a serverContext called " + name);
foundContexts++;
}
}
/**
* If there is only once instance of DWR defined in a ServletContext then
* we can get at it using this method.
* @return The one-and-only ServerContext or null if there are more than 1.
*/
public static ServerContext getSingletonServerContext()
{
synchronized (contextMap)
{
return singletonServerContext;
}
}
/**
* Returns a Collection of all ServerContexts in which DWR has been defined.
* @return Collection of ServerContexts.
*/
public static Collection<ServerContext> getAllServerContexts()
{
Collection<ServerContext> reply = new ArrayList<ServerContext>();
reply.addAll(contextMap.values());
return Collections.unmodifiableCollection(reply);
}
/**
* Get a list of all known Containers for the given {@link ServletContext}
* @param servletContext The context in which {@link Container}s are stored.
* @return a list of published {@link Container}s.
*/
@SuppressWarnings("unchecked")
public static List<Container> getAllPublishedContainers(ServletContext servletContext)
{
List<Container> reply = new ArrayList<Container>();
List<Container> containers = (List<Container>) servletContext.getAttribute(ATTRIBUTE_CONTAINER_LIST);
if (containers != null)
{
reply.addAll(containers);
}
return reply;
}
/**
* Create a bunch of debug information about a container
* @param container The container to print debug information about
*/
public static void debugConfig(Container container)
{
if (Loggers.STARTUP.isDebugEnabled())
{
// Container level debug
Loggers.STARTUP.debug("Container");
Loggers.STARTUP.debug(" Type: " + container.getClass().getName());
for (String name : container.getBeanNames())
{
Object object = container.getBean(name);
if (object instanceof String)
{
Loggers.STARTUP.debug(" Param: " + name + " = " + object + " (" + object.getClass().getName() + ")");
}
else
{
Loggers.STARTUP.debug(" Bean: " + name + " = " + object + " (" + object.getClass().getName() + ")");
}
}
// AccessControl debugging
AccessControl accessControl = container.getBean(AccessControl.class);
Loggers.STARTUP.debug("AccessControl");
Loggers.STARTUP.debug(" Type: " + accessControl.getClass().getName());
// AjaxFilterManager debugging
AjaxFilterManager ajaxFilterManager = container.getBean(AjaxFilterManager.class);
Loggers.STARTUP.debug("AjaxFilterManager");
Loggers.STARTUP.debug(" Type: " + ajaxFilterManager.getClass().getName());
// ConverterManager debugging
ConverterManager converterManager = container.getBean(ConverterManager.class);
Loggers.STARTUP.debug("ConverterManager");
Loggers.STARTUP.debug(" Type: " + converterManager.getClass().getName());
// CreatorManager debugging
CreatorManager creatorManager = container.getBean(CreatorManager.class);
Loggers.STARTUP.debug("CreatorManager");
Loggers.STARTUP.debug(" Type: " + creatorManager.getClass().getName());
for (String creatorName : creatorManager.getCreatorNames(false))
{
Creator creator = creatorManager.getCreator(creatorName, false);
Loggers.STARTUP.debug(" Creator: " + creatorName + " = " + creator + " (" + creator.getClass().getName() + ")");
}
// ModuleManager debugging
ModuleManager moduleManager = container.getBean(ModuleManager.class);
Loggers.STARTUP.debug("ModuleManager");
Loggers.STARTUP.debug(" Type: " + moduleManager.getClass().getName());
}
}
/**
* We store a single ServerContext in the contextMap under this name.
*/
private static ServerContext singletonServerContext;
/**
* To enable us to get at a complete list of all {@link ServerContext}s
*/
private static final Map<String, ServerContext> contextMap = new HashMap<String, ServerContext>();
/**
* How many Contexts are there in this classloader that we need to
* distinguish? Things will be a lot harder if there is more than 1.
*/
private static int foundContexts = 0;
}