Package com.kurento.kmf.content.internal.base

Source Code of com.kurento.kmf.content.internal.base.AbstractContentHandlerServlet

/*
* (C) Copyright 2013 Kurento (http://kurento.org/)
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Lesser General Public License
* (LGPL) version 2.1 which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/lgpl-2.1.html
*
* This library 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.
*
*/
package com.kurento.kmf.content.internal.base;

import static com.kurento.kmf.content.jsonrpc.JsonRpcConstants.METHOD_EXECUTE;
import static com.kurento.kmf.content.jsonrpc.JsonRpcConstants.METHOD_START;

import java.io.IOException;
import java.util.concurrent.Future;

import javax.servlet.AsyncContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.kurento.kmf.common.exception.KurentoMediaFrameworkException;
import com.kurento.kmf.common.exception.internal.ExceptionUtils;
import com.kurento.kmf.common.exception.internal.ServletUtils;
import com.kurento.kmf.content.ContentHandler;
import com.kurento.kmf.content.ContentSession;
import com.kurento.kmf.content.internal.ContentApiExecutorService;
import com.kurento.kmf.content.internal.ContentApiWebApplicationInitializer;
import com.kurento.kmf.content.internal.ContentAsyncListener;
import com.kurento.kmf.content.internal.ContentSessionManager;
import com.kurento.kmf.content.internal.ControlProtocolManager;
import com.kurento.kmf.content.internal.RejectableRunnable;
import com.kurento.kmf.content.jsonrpc.JsonRpcRequest;
import com.kurento.kmf.content.jsonrpc.JsonRpcResponse;
import com.kurento.kmf.spring.KurentoApplicationContextUtils;

/**
*
* Abstract class with the definition for Handler Servlets.
*
* @author Luis López (llopez@gsyc.es)
* @version 1.0.0
*/
public abstract class AbstractContentHandlerServlet extends HttpServlet {

  private static final long serialVersionUID = 1L;

  @Autowired
  private ContentApiExecutorService executor;

  @Autowired
  private ControlProtocolManager protocolManager;

  @Autowired
  protected ContentHandler<? extends ContentSession> handler;

  protected ContentSessionManager contentSessionManager;

  // protected boolean useRedirectStrategy = true;
  protected Class<?> handlerClass;

  protected boolean useControlProtocol = false;

  protected abstract boolean getUseJsonControlProtocol(Class<?> handlerClass)
      throws ServletException;

  protected abstract AbstractContentSession createContentSession(
      AsyncContext asyncCtx, String contentId);

  protected abstract Logger getLogger();

  @Override
  public void init() throws ServletException {
    super.init();

    // Recover application context associated to this servlet in this
    // context
    AnnotationConfigApplicationContext thisServletContext = KurentoApplicationContextUtils
        .getKurentoServletApplicationContext(this.getClass(),
            this.getServletName());

    // If there is not application context associated to this servlet,
    // create one
    if (thisServletContext == null) {
      // Locate the handler class associated to this servlet
      String handlerClassName = this
          .getInitParameter(ContentApiWebApplicationInitializer.HANDLER_CLASS_PARAM_NAME);
      if (handlerClassName == null || handlerClassName.equals("")) {
        String message = "Cannot find handler class associated to handler servlet with name "
            + this.getServletConfig().getServletName()
            + " and class " + this.getClass().getName();
        getLogger().error(message);
        throw new ServletException(message);
      }
      // Create application context for this servlet containing the
      // handler
      thisServletContext = KurentoApplicationContextUtils
          .createKurentoHandlerServletApplicationContext(
              this.getClass(), this.getServletName(),
              this.getServletContext(), handlerClassName);

      // useRedirectStrategy = getUseRedirectStrategy(handlerClass);
      try {
        handlerClass = Class.forName(handlerClassName);
      } catch (ClassNotFoundException e) {
        String message = "Cannot recover class " + handlerClass
            + " on classpath";
        getLogger().error(message);
        throw new ServletException(message);
      }
      useControlProtocol = getUseJsonControlProtocol(handlerClass);
    }

    // Make this servlet to receive beans to resolve the @Autowired present
    // on it
    KurentoApplicationContextUtils
        .processInjectionBasedOnApplicationContext(this,
            thisServletContext);

    if (useControlProtocol) {
      contentSessionManager = (ContentSessionManager) KurentoApplicationContextUtils
          .getBean("contentSessionManager");
    }

  }

  @Override
  protected final void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    if (useControlProtocol) {
      ServletUtils
          .sendHttpError(
              req,
              resp,
              HttpServletResponse.SC_NOT_IMPLEMENTED,
              "Only POST request are supported for this service. You can enable GET requests "
                  + " by setting useControlProtocol to false on the appropriate handler annotation");
      return;
    }

    getLogger().info("GET request received: " + req.getRequestURI());

    if (!req.isAsyncSupported()) {
      // Async context could not be created. It is not necessary to
      // complete it. Just send error message to
      ServletUtils
          .sendHttpError(
              req,
              resp,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              "AsyncContext could not be started. The application should add \"asyncSupported = true\" in all "
                  + this.getClass().getName()
                  + " instances and in all filters in the associated chain");
      return;
    }
    if (handler == null) {
      ServletUtils
          .sendHttpError(
              req,
              resp,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              handler.getClass().getSimpleName()
                  + " is null. This error means that you "
                  + "need to provide a valid implementation of interface "
                  + handler.getClass().getSimpleName());
      return;
    }

    String contentId = req.getPathInfo();
    if (contentId != null) {
      contentId = contentId.substring(1);
    }

    AsyncContext asyncCtx = req.startAsync();

    // Add listener for managing error conditions
    asyncCtx.addListener(new ContentAsyncListener());

    doRequest4SimpleHttpProtocol(asyncCtx, contentId, resp);

  }

  @Override
  protected final void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {

    getLogger().info("POST request received: " + req.getRequestURI());

    if (!req.isAsyncSupported()) {
      // Async context could not be created. It is not necessary to
      // complete it. Just send error message to
      ServletUtils
          .sendHttpError(
              req,
              resp,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              "AsyncContext could not be started. The application should add \"asyncSupported = true\" in all "
                  + this.getClass().getName()
                  + " instances and in all filters in the associated chain");
      return;
    }
    if (handler == null) {
      ServletUtils
          .sendHttpError(
              req,
              resp,
              HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
              handler.getClass().getSimpleName()
                  + " is null. This error means that you "
                  + "need to provide a valid implementation of interface "
                  + handler.getClass().getSimpleName());
      return;
    }

    String contentId = req.getPathInfo();
    if (contentId != null) {
      contentId = contentId.substring(1);
    }

    AsyncContext asyncCtx = req.startAsync();

    // Add listener for managing error conditions
    asyncCtx.addListener(new ContentAsyncListener());

    if (useControlProtocol) {
      doRequest4JsonControlProtocol(asyncCtx, contentId, resp);
    } else {
      // TODO: we should check that the content type correspond to
      // the ones we support. We should avoid receiving application/json
      // here and send a coherent error message in that case because this
      // case corresponds to using incorrectly annotations on handlers
      doRequest4SimpleHttpProtocol(asyncCtx, contentId, resp);
    }
  }

  /**
   * Generic processor of HTTP request when not using JSON control procotol.
   *
   * @param asyncCtx
   *            Asynchronous context
   * @param contentId
   *            Content unique identifier
   * @param resp
   *            HTTP response
   * @throws ServletException
   *             Exception in Servlet
   * @throws IOException
   *             Input/Ouput Exception
   */
  private void doRequest4SimpleHttpProtocol(AsyncContext asyncCtx,
      String contentId, HttpServletResponse resp)
      throws ServletException, IOException {
    try {
      AbstractContentSession contentRequest = createContentSession(
          asyncCtx, contentId);

      Future<?> future = executor.getExecutor()
          .submit(createAsyncRequestProcessor(contentRequest, null,
              asyncCtx));
      // Store future and request for using it in case of error
      asyncCtx.getRequest().setAttribute(
          ContentAsyncListener.FUTURE_REQUEST_PROCESSOR_ATT_NAME,
          future);
      asyncCtx.getRequest().setAttribute(
          ContentAsyncListener.CONTENT_REQUEST_ATT_NAME,
          contentRequest);
    } catch (KurentoMediaFrameworkException ke) {
      getLogger().error(ke.getMessage(), ke);
      ServletUtils.sendHttpError(
          (HttpServletRequest) asyncCtx.getRequest(), resp,
          ExceptionUtils.getHttpErrorCode(ke.getCode()),
          ke.getMessage());
    }
  }

  /**
   * Generic processor of HTTP request when using JSON control protocol.
   *
   * @param asyncCtx
   *            Asynchronous context
   * @param contentId
   *            Content unique identifier
   * @param resp
   *            HTTP response
   * @throws ServletException
   *             Exception in servlet
   * @throws IOException
   *             Input/Ouput Exception
   */
  private void doRequest4JsonControlProtocol(AsyncContext asyncCtx,
      String contentId, HttpServletResponse resp)
      throws ServletException, IOException {

    JsonRpcRequest message = null;

    try {
      message = protocolManager.receiveJsonRequest(asyncCtx);

      if (message == null) {
        throw new KurentoMediaFrameworkException(
            "Null json message received", 10020);
      }

      AbstractContentSession contentSession = null;
      String sessionId = message.getParams() != null ? message
          .getParams().getSessionId() : null;

      if (sessionId == null && message.getMethod().equals(METHOD_START)) {
        // Session is created by a start request, we need to fill
        // asyncCtx associated to start requests.
        contentSession = createContentSession(asyncCtx, contentId);
        contentSessionManager.put(contentSession);
      } else if (sessionId == null
          && message.getMethod().equals(METHOD_EXECUTE)) {
        // Session is created by an execute request, the asyncCtx for
        // start requests must be set to null
        contentSession = createContentSession(null, contentId);
        contentSessionManager.put(contentSession);
      } else if (sessionId != null) {
        contentSession = contentSessionManager.get(sessionId);
        if (contentSession == null) {
          throw new KurentoMediaFrameworkException(
              "Could not find contentSession object associated to sessionId "
                  + sessionId, 10021);
        }
      } else {
        throw new KurentoMediaFrameworkException(
            "Could not find required sessionId field in request",
            10022);
      }

      Future<?> future = executor.getExecutor().submit(
          createAsyncRequestProcessor(contentSession, message,
              asyncCtx));

      // Store future for using it in ContentAsyncListener in case of
      // error
      asyncCtx.getRequest().setAttribute(
          ContentAsyncListener.FUTURE_REQUEST_PROCESSOR_ATT_NAME,
          future);
      asyncCtx.getRequest().setAttribute(
          ContentAsyncListener.CONTENT_REQUEST_ATT_NAME,
          contentSession);
      asyncCtx.getRequest()
          .setAttribute(
              ContentAsyncListener.CONTROL_PROTOCOL_REQUEST_MESSAGE_ATT_NAME,
              message);
    } catch (KurentoMediaFrameworkException ke) {
      int reqId = message != null ? message.getId() : 0;
      protocolManager.sendJsonError(
          asyncCtx,
          JsonRpcResponse.newError(
              ExceptionUtils.getJsonErrorCode(ke.getCode()),
              ke.getMessage(), reqId));
    } catch (Throwable t) {
      int reqId = message != null ? message.getId() : 0;
      protocolManager.sendJsonError(asyncCtx, JsonRpcResponse.newError(
          ExceptionUtils.getJsonErrorCode(1), t.getMessage(), reqId));
    }
  }

  private RejectableRunnable createAsyncRequestProcessor(
      AbstractContentSession contentRequest, JsonRpcRequest message,
      AsyncContext asyncCtx) {
    return (AsyncContentRequestProcessor) KurentoApplicationContextUtils
        .getBean("asyncContentRequestProcessor", contentRequest,
            message, asyncCtx);
  }
}
TOP

Related Classes of com.kurento.kmf.content.internal.base.AbstractContentHandlerServlet

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.