All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.phloc.web.mock.MockServletPool Maven / Gradle / Ivy

/**
 * Copyright (C) 2006-2015 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * 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 com.phloc.web.mock;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phloc.commons.ValueEnforcer;
import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.lang.GenericReflection;
import com.phloc.commons.regex.RegExHelper;
import com.phloc.commons.string.StringHelper;
import com.phloc.commons.string.ToStringGenerator;

/**
 * A pool for registered servlets inside a {@link MockServletContext}.
 * 
 * @author Philip Helger
 */
@NotThreadSafe
public class MockServletPool
{
  /**
   * Contains a single servlet item
   * 
   * @author Philip Helger
   */
  private static final class ServletItem
  {
    private final Servlet m_aServlet;
    private final String m_sServletPath;
    private final String m_sServletPathRegEx;

    @Nonnull
    @Nonempty
    private static String _getAsRegEx (@Nonnull @Nonempty final String sPath)
    {
      String sPathToUse = sPath;
      if (sPathToUse.endsWith ("/*"))
      {
        // Special handling for trailing "/*" which means that a servlet
        // registered for "/test/*" can be found with the servlet path "/test".
        sPathToUse = sPath.substring (0, sPath.length () - 2);
      }

      // Convert wildcard to regex
      return StringHelper.replaceAll (sPathToUse, "*", ".*");
    }

    public ServletItem (@Nonnull final Servlet aServlet, @Nonnull @Nonempty final String sServletPath)
    {
      m_aServlet = ValueEnforcer.notNull (aServlet, "Servlet");
      m_sServletPath = ValueEnforcer.notEmpty (sServletPath, "ServletPath");
      m_sServletPathRegEx = _getAsRegEx (sServletPath);
    }

    @Nonnull
    public Servlet getServlet ()
    {
      return m_aServlet;
    }

    @Nonnull
    @Nonempty
    public String getServletName ()
    {
      return m_aServlet.getServletConfig ().getServletName ();
    }

    @Nonnull
    @Nonempty
    public String getServletPath ()
    {
      return m_sServletPath;
    }

    public boolean matchesPath (@Nonnull final String sServletPath)
    {
      return RegExHelper.stringMatchesPattern (m_sServletPathRegEx, sServletPath);
    }

    @Override
    public String toString ()
    {
      return new ToStringGenerator (this).append ("servlet", m_aServlet)
                                         .append ("servletPath", m_sServletPath)
                                         .toString ();
    }
  }

  private static final Logger s_aLogger = LoggerFactory.getLogger (MockServletPool.class);

  private final MockServletContext m_aSC;
  private final List  m_aServlets = new ArrayList  ();
  private boolean m_bInvalidated = false;

  public MockServletPool (@Nonnull final MockServletContext aSC)
  {
    m_aSC = ValueEnforcer.notNull (aSC, "ServletContext");
  }

  /**
   * Register a new servlet without servlet init parameters
   * 
   * @param aServletClass
   *        The class of the servlet to be registered. May not be
   *        null.
   * @param sServletPath
   *        The path where the servlet should listen to requests. May neither be
   *        null nor empty.
   * @param sServletName
   *        The name of the servlet. May neither be null nor empty.
   */
  public void registerServlet (@Nonnull final Class  aServletClass,
                               @Nonnull @Nonempty final String sServletPath,
                               @Nonnull @Nonempty final String sServletName)
  {
    registerServlet (aServletClass, sServletPath, sServletName, (Map ) null);
  }

  /**
   * Register a new servlet
   * 
   * @param aServletClass
   *        The class of the servlet to be registered. May not be
   *        null.
   * @param sServletPath
   *        The path where the servlet should listen to requests. May neither be
   *        null nor empty.
   * @param sServletName
   *        The name of the servlet. May neither be null nor empty.
   * @param aServletInitParams
   *        An optional map of servlet init parameters. May be null
   *        or empty.
   */
  public void registerServlet (@Nonnull final Class  aServletClass,
                               @Nonnull @Nonempty final String sServletPath,
                               @Nonnull @Nonempty final String sServletName,
                               @Nullable final Map  aServletInitParams)
  {
    ValueEnforcer.notNull (aServletClass, "ServletClass");
    ValueEnforcer.notEmpty (sServletPath, "ServletPath");

    for (final ServletItem aItem : m_aServlets)
    {
      // Check path uniqueness
      if (aItem.getServletPath ().equals (sServletPath))
        throw new IllegalArgumentException ("Another servlet with the path '" +
                                            sServletPath +
                                            "' is already registered: " +
                                            aItem);
      // Check name uniqueness
      if (aItem.getServletName ().equals (sServletName))
        throw new IllegalArgumentException ("Another servlet with the name '" +
                                            sServletName +
                                            "' is already registered: " +
                                            aItem);
    }

    // Instantiate servlet
    final Servlet aServlet = GenericReflection.newInstance (aServletClass);
    if (aServlet == null)
      throw new IllegalArgumentException ("Failed to instantiate servlet class " + aServletClass);

    final ServletConfig aServletConfig = m_aSC.createServletConfig (sServletName, aServletInitParams);
    try
    {
      aServlet.init (aServletConfig);
    }
    catch (final ServletException ex)
    {
      throw new IllegalStateException ("Failed to init servlet " +
                                       aServlet +
                                       " with configuration  " +
                                       aServletConfig +
                                       " for path '" +
                                       sServletPath +
                                       "'");
    }
    m_aServlets.add (new ServletItem (aServlet, sServletPath));
  }

  /**
   * Find the servlet matching the specified path.
   * 
   * @param sPath
   *        The path, relative to the servlet context. May be null.
   * @return null if no {@link Servlet} matching the specified path
   *         was found. If more than one matching servlet was found, the first
   *         one is returned.
   */
  @Nullable
  public Servlet getServletOfPath (@Nullable final String sPath)
  {
    final List  aMatchingItems = new ArrayList  ();
    if (StringHelper.hasText (sPath))
      for (final ServletItem aItem : m_aServlets)
        if (aItem.matchesPath (sPath))
          aMatchingItems.add (aItem);
    final int nMatchingItems = aMatchingItems.size ();
    if (nMatchingItems == 0)
      return null;
    if (nMatchingItems > 1)
      s_aLogger.warn ("Found more than 1 servlet matching path '" + sPath + "' - using first one: " + aMatchingItems);
    return ContainerHelper.getFirstElement (aMatchingItems).getServlet ();
  }

  /**
   * Invalidate the servlet pool, by destroying all contained servlets. Also the
   * list of registered servlets is cleared.
   */
  public void invalidate ()
  {
    if (m_bInvalidated)
      throw new IllegalArgumentException ("Servlet pool already invalidated!");
    m_bInvalidated = true;

    // Destroy all servlets
    for (final ServletItem aServletItem : m_aServlets)
      try
      {
        aServletItem.getServlet ().destroy ();
      }
      catch (final Throwable t)
      {
        s_aLogger.error ("Failed to destroy servlet " + aServletItem, t);
      }

    m_aServlets.clear ();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy