Package org.pentaho.platform.web.servlet

Source Code of org.pentaho.platform.web.servlet.PluginDispatchServlet

/*!
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* 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.
*
* Copyright (c) 2002-2013 Pentaho Corporation..  All rights reserved.
*/

package org.pentaho.platform.web.servlet;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.platform.api.engine.IPluginManager;
import org.pentaho.platform.api.engine.IPluginManagerListener;
import org.pentaho.platform.engine.core.system.PentahoSystem;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.ListableBeanFactory;

import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
* Dispatches requests to Servlets provided by BIServer plugins. To define a Servlet in a plugin, simply add a bean
* element for the Servlet class in the plugin.spring.xml file in your plugin root directory.
*
* @author Aaron Phillips
*/
public class PluginDispatchServlet implements Servlet {

  private static final Log logger = LogFactory.getLog( PluginDispatchServlet.class );

  private ServletConfig servletConfig;

  private boolean initialized = false;

  private IPluginManager pluginManager = PentahoSystem.get( IPluginManager.class );

  private Map<String, Servlet> pluginServletMap = new HashMap<String, Servlet>();

  public PluginDispatchServlet() {
    super();
  }

  public void destroy() {
    for ( Map.Entry<String, Servlet> pluginServlet : pluginServletMap.entrySet() ) {
      pluginServlet.getValue().destroy();
    }
  }

  public void service( final ServletRequest req, final ServletResponse res ) throws ServletException, IOException {
    if ( !initialized ) {
      doInit();
    }
    if ( !( req instanceof HttpServletRequest ) ) {
      throw new IllegalArgumentException( PluginDispatchServlet.class.getSimpleName()
        + " cannot handle non HTTP requests" ); //$NON-NLS-1$
    }

    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    Servlet pluginServlet = getTargetServlet( request, response );

    if ( pluginServlet == null ) {
      response.setStatus( 404 );
      // FIXME: log more detail here for debugging
      return;
    }

    pluginServlet.service( req, res );
  }

  protected Servlet getTargetServlet( HttpServletRequest request, HttpServletResponse response )
    throws ServletException {
    String dispatchKey = getDispatchKey( request );

    if ( StringUtils.isEmpty( dispatchKey ) ) {
      if ( logger.isDebugEnabled() ) {
        logger
          .debug( "dispatcher servlet is invoked but there is nothing telling it where to dispatch to" ); //$NON-NLS-1$
      }
      return null;
    }

    Servlet targetServlet = null;
    String checkPath = dispatchKey;
    do {
      logger.debug(
        "checking for servlet registered to service request for \"" + checkPath + "\"" ); //$NON-NLS-1$//$NON-NLS-2$
      targetServlet = pluginServletMap.get( checkPath );
      if ( targetServlet != null ) {
        logger.debug( "servlet " + targetServlet.getClass().getName() + " will service request for \"" + dispatchKey
          //$NON-NLS-1$//$NON-NLS-2$
          + "\"" ); //$NON-NLS-1$
        return targetServlet;
      }
      if ( checkPath.contains( "/" ) ) { //$NON-NLS-1$
        checkPath = checkPath.substring( 0, checkPath.lastIndexOf( "/" ) ); //$NON-NLS-1$
      } else {
        checkPath = null;
      }
    } while ( checkPath != null );

    if ( targetServlet == null ) {
      logger
        .debug( "no servlet registered to service request for \"" + dispatchKey + "\"" ); //$NON-NLS-1$ //$NON-NLS-2$
    }
    return targetServlet;
  }

  /**
   * Returns the dispatch key for this request. This name is the part of the request path beyond the servlet base path.
   * I.e. if the PluginDispatchServlet is mapped to the "/plugin" context in web.xml, then this method will return
   * "myPlugin/myServlet" given a request to "http://localhost:8080/pentaho/plugin/myPlugin/myServlet".
   *
   * @return the part of the request url used to dispatch the request
   */
  public String getDispatchKey( HttpServletRequest request ) {
    // path info will give us what we want with
    String requestPathInfo = request.getPathInfo();
    if ( requestPathInfo.startsWith( "/" ) ) { //$NON-NLS-1$
      requestPathInfo = requestPathInfo.substring( 1 );
    }
    if ( requestPathInfo.endsWith( "/" ) ) { //$NON-NLS-1$
      requestPathInfo = requestPathInfo.substring( requestPathInfo.length() );
    }
    return requestPathInfo;
  }

  public void init( final ServletConfig config ) throws ServletException {
    this.servletConfig = config;
    pluginManager.addPluginManagerListener( new IPluginManagerListener() {
      @Override public void onReload() {
        try {
          initialized = false;
          doInit();
        } catch ( ServletException e ) {
          logger.error( e );
        }
      }
    } );
    doInit();
  }

  @SuppressWarnings( "unchecked" )
  /** Restore the caching once the Plugin Type Tracking system is in place, for now we'll look-up every time **/
  private synchronized void doInit() throws ServletException {
    if ( logger.isDebugEnabled() ) {
      logger.debug( "PluginDispatchServlet.init" ); //$NON-NLS-1$
    }

    if ( initialized ) {
      return;
    }
    pluginServletMap.clear();

    Map<String, ListableBeanFactory> pluginBeanFactoryMap = getPluginBeanFactories();

    for ( Map.Entry<String, ListableBeanFactory> pluginBeanFactoryEntry : pluginBeanFactoryMap.entrySet() ) {

      Map<String, Object> beans =
        BeanFactoryUtils.beansOfTypeIncludingAncestors( pluginBeanFactoryEntry.getValue(),
          Servlet.class, true, true );

      if ( logger.isDebugEnabled() ) {
        logger.debug(
          "found " + beans.size() + " servlets in " + pluginBeanFactoryEntry.getKey() ); //$NON-NLS-1$//$NON-NLS-2$
      }

      for ( Map.Entry<String, Object> beanEntry : beans.entrySet() ) {
        Servlet pluginServlet = (Servlet) beanEntry.getValue();
        String servletId = beanEntry.getKey();

        String pluginId = pluginBeanFactoryEntry.getKey();
        String context = pluginId + "/" + servletId; //$NON-NLS-1$

        pluginServletMap.put( context, pluginServlet );
        if ( logger.isDebugEnabled() ) {
          logger
            .debug( "calling init on servlet " + pluginServlet.getClass().getName() + " serving context "
              + context ); //$NON-NLS-1$//$NON-NLS-2$
        }
        try {
          pluginServlet.init( servletConfig );
        } catch ( Throwable t ) {
          logger.error( "Could not load servlet '" + context + "'", t ); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        }
      }
    }

    // Set initialized to true at the end of the synchronized method, so
    // that invocations of service() before this method has completed will not
    // cause NullPointerException
    initialized = true;
  }

  public ServletConfig getServletConfig() {
    return servletConfig;
  }

  public String getServletInfo() {
    return "A servlet to dispatch requests to Servlets defined in BIServer plugins"; //$NON-NLS-1$
  }

  protected Map<String, ListableBeanFactory> getPluginBeanFactories() {
    Collection<String> pluginIds = pluginManager.getRegisteredPlugins();
    Map<String, ListableBeanFactory> pluginBeanFactoryMap = new HashMap<String, ListableBeanFactory>();
    for ( String pluginId : pluginIds ) {
      ListableBeanFactory beanFactory = pluginManager.getBeanFactory( pluginId );
      if ( beanFactory != null ) {
        pluginBeanFactoryMap.put( pluginId, beanFactory );
      }
    }
    return pluginBeanFactoryMap;
  }
}
TOP

Related Classes of org.pentaho.platform.web.servlet.PluginDispatchServlet

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.