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

org.eclipse.rap.rwt.engine.RWTServlet Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2002, 2024 Innoopract Informationssysteme GmbH and others.
 * 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:
 *    Innoopract Informationssysteme GmbH - initial API and implementation
 *    EclipseSource - ongoing implementation
 *    Frank Appel - replaced singletons and static fields (Bug 337787)
 ******************************************************************************/
package org.eclipse.rap.rwt.engine;

import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND;
import static jakarta.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
import static org.eclipse.rap.rwt.internal.protocol.ClientMessageConst.CONNECTION_ID;
import static org.eclipse.rap.rwt.internal.util.HTTP.CONTENT_TYPE_JSON;
import static org.eclipse.rap.rwt.internal.util.HTTP.METHOD_POST;

import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.eclipse.rap.rwt.internal.application.ApplicationContextImpl;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.internal.service.ServiceContext;
import org.eclipse.rap.rwt.internal.service.ServiceManagerImpl;
import org.eclipse.rap.rwt.internal.service.ServiceStore;
import org.eclipse.rap.rwt.internal.service.StartupJson;
import org.eclipse.rap.rwt.internal.service.UISessionBuilder;
import org.eclipse.rap.rwt.internal.service.UISessionImpl;
import org.eclipse.rap.rwt.internal.util.HTTP;
import org.eclipse.rap.rwt.service.ServiceHandler;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;


/**
 * The RWT servlet. This servlet receives all requests to a RAP application.
 * 

* Usually, you only have to register this servlet manually in a traditional web * application, i.e. without OSGi. *

*

* In a traditional web application (without OSGi), this servlet must be * registered in the application's deployment descriptor like shown below. Note * that the RWT servlet has to be registered for every entrypoint of the * application. *

* *
 * <context-param>
 *   <param-name>org.eclipse.rap.applicationConfiguration</param-name>
 *   <param-value>com.example.HelloWorldConfiguration</param-value>
 * </context-param>
 *
 * <listener>
 *   <listener-class>org.eclipse.rap.rwt.engine.RWTServletContextListener</listener-class>
 * </listener>
 *
 * <servlet>
 *   <servlet-name>rwtServlet</servlet-name>
 *   <servlet-class>org.eclipse.rap.rwt.engine.RWTServlet</servlet-class>
 * </servlet>
 *
 * <servlet-mapping>
 *   <servlet-name>rwtServlet</servlet-name>
 *   <url-pattern>/example</url-pattern>
 * </servlet-mapping>
 *
 * 
 *
 * @since 2.0
 * @noextend This class is not intended to be subclassed by clients.
 */
public class RWTServlet extends HttpServlet {

  private ApplicationContextImpl applicationContext;

  @Override
  public String getServletInfo() {
    return "RWT Servlet";
  }

  @Override
  public void init() throws ServletException {
    ServletContext servletContext = getServletContext();
    applicationContext = ApplicationContextImpl.getFrom( servletContext );
  }

  @Override
  public void doGet( HttpServletRequest request, HttpServletResponse response )
    throws ServletException, IOException
  {
    handleRequest( request, response );
  }

  @Override
  public void doPost( HttpServletRequest request, HttpServletResponse response )
    throws ServletException, IOException
  {
    ensureCharacterEncoding( request );
    handleRequest( request, response );
  }

  private void handleRequest( HttpServletRequest request, HttpServletResponse response )
    throws IOException, ServletException
  {
    if( !applicationContext.allowsRequests() ) {
      response.sendError( SC_SERVICE_UNAVAILABLE );
    } else if( request.getPathInfo() == null ) {
      // /context/servlet: no extra path info after servlet name
      handleValidRequest( request, response );
    } else if( "/".equals( request.getPathInfo() ) && "".equals( request.getServletPath() ) ) {
      // /context/: root servlet, in this case path info "/" is ok
      handleValidRequest( request, response );
    } else {
      response.sendError( SC_NOT_FOUND );
    }
  }

  private void handleValidRequest( HttpServletRequest request, HttpServletResponse response )
    throws IOException, ServletException
  {
    ServiceContext context = new ServiceContext( request, response, applicationContext );
    context.setServiceStore( new ServiceStore() );
    ContextProvider.setContext( context );
    try {
      prepareUISession( context );
      if( isUIRequest( request ) || isServiceHandlerRequest( request ) ) {
        getServiceHandler().service( request, response );
      } else {
        sendStartupContent( request, response );
      }
    } finally {
      ContextProvider.disposeContext();
    }
  }

  private ServiceHandler getServiceHandler() {
    return applicationContext.getServiceManager().getHandler();
  }

  private static boolean isUIRequest( HttpServletRequest request ) {
    return    METHOD_POST.equals( request.getMethod() )
           && isContentTypeValid( request )
           && !isServiceHandlerRequest( request );
  }

  private static boolean isServiceHandlerRequest( HttpServletRequest request ) {
    return request.getParameter( ServiceManagerImpl.REQUEST_PARAM ) != null;
  }

  private static boolean isContentTypeValid( ServletRequest request ) {
    String contentType = request.getContentType();
    return contentType != null && contentType.startsWith( CONTENT_TYPE_JSON );
  }

  private void sendStartupContent( HttpServletRequest request, HttpServletResponse response )
    throws IOException
  {
    String accept = request.getHeader( HTTP.HEADER_ACCEPT );
    if( accept != null && accept.contains( HTTP.CONTENT_TYPE_JSON ) ) {
      StartupJson.send( response );
    } else {
      applicationContext.getStartupPage().send( response );
    }
  }

  private static void prepareUISession( ServiceContext context ) {
    HttpServletRequest request = context.getRequest();
    HttpSession httpSession = request.getSession( true );
    String connectionId = request.getParameter( CONNECTION_ID );
    if( connectionId != null ) {
      context.setUISession( UISessionImpl.getInstanceFromSession( httpSession, connectionId ) );
    } else if( isUIRequest( request ) ) {
      context.setUISession( new UISessionBuilder( context ).buildUISession() );
    }
  }

  private static void ensureCharacterEncoding( HttpServletRequest request ) {
    try {
      /*
       * For POST request we can set the character encoding and get the properly decoded
       * parameters via HttpServletRequest.getParameterMap API.
       */
      String characterEncoding = request.getCharacterEncoding();
      if( characterEncoding == null || characterEncoding.isEmpty() ) {
        request.setCharacterEncoding( HTTP.CHARSET_UTF_8 );
      }
    } catch ( @SuppressWarnings( "unused" ) UnsupportedEncodingException ex ) {
      // should never happen
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy