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

org.perfcake.message.sender.WebSocketSender Maven / Gradle / Ivy

There is a newer version: 7.5
Show newest version
/*
 * -----------------------------------------------------------------------\
 * PerfCake
 *  
 * Copyright (C) 2010 - 2016 the original author or authors.
 *  
 * 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.perfcake.message.sender;

import org.perfcake.PerfCakeException;
import org.perfcake.message.Message;
import org.perfcake.reporting.MeasurementUnit;
import org.perfcake.util.Utils;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.Properties;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

/**
 * Sends a simple messages via websocket protocol to a remote websocket server endpoint.
 *
 * @author Jiří Sviták
 */
public class WebSocketSender extends AbstractSender {

   private static final Logger logger = LogManager.getLogger(WebSocketSender.class);

   private WebSocketContainer container;
   private Session session;

   /**
    * Remote endpoint type.
    *
    * @author Jiří Sviták
    */
   public enum RemoteEndpointType {
      BASIC, ASYNC
   }

   private RemoteEndpointType remoteEndpointType = RemoteEndpointType.BASIC;

   /**
    * Payload type.
    *
    * @author Jiří Sviták
    */
   public enum PayloadType {
      TEXT, BINARY, PING
   }

   private PayloadType payloadType = PayloadType.TEXT;

   /**
    * Sets remote endpoint type.
    *
    * @param remoteEndpointType
    *       The remote endpoint type. The value should be one of basic or async.
    * @return Instance of this to support fluent API.
    */
   public WebSocketSender setRemoteEndpointType(final String remoteEndpointType) {
      switch (remoteEndpointType) {
         case "basic":
            this.remoteEndpointType = RemoteEndpointType.BASIC;
            break;
         case "async":
            this.remoteEndpointType = RemoteEndpointType.ASYNC;
            break;
         default:
            throw new IllegalStateException("Unknown or undefined web socket remote endpoint type. Use either basic or async.");
      }

      return this;
   }

   /**
    * Sets payload type.
    *
    * @param payloadType
    *       The remote endpoint type. The value should be one of text, binary or ping.
    * @return Instance of this to support fluent API.
    */
   public WebSocketSender setPayloadType(final String payloadType) {
      switch (payloadType) {
         case "text":
            this.payloadType = PayloadType.TEXT;
            break;
         case "binary":
            this.payloadType = PayloadType.BINARY;
            break;
         case "ping":
            this.payloadType = PayloadType.PING;
            break;
         default:
            throw new IllegalStateException("Unknown or undefined web socket payload type. Use text, binary, or ping.");
      }

      return this;
   }

   @Override
   public void doInit(final Properties messageAttributes) throws PerfCakeException {
      container = ContainerProvider.getWebSocketContainer();
      try {
         final String safeTarget = safeGetTarget(messageAttributes);

         if (logger.isTraceEnabled()) {
            logger.trace("Connecting to URI " + safeTarget);
         }

         container.connectToServer(new PerfCakeClientEndpoint(), new URI(safeTarget));
      } catch (IOException | DeploymentException | URISyntaxException e) {
         throw new PerfCakeException("Cannot open web socket: ", e);
      }
      if (session == null) {
         throw new PerfCakeException("Web socket session cannot be null before the scenario run.");
      }
   }

   @Override
   public void doClose() throws PerfCakeException {
      try {
         session.close();
      } catch (final IOException e) {
         throw new PerfCakeException("Cannot close web socket session.", e);
      }
   }

   @Override
   public Serializable doSend(final Message message, final MeasurementUnit measurementUnit) throws Exception {
      RemoteEndpoint endpoint;
      switch (remoteEndpointType) {
         default: // to get rid of a compiler warning
         case BASIC:
            endpoint = session.getBasicRemote();
            break;
         case ASYNC:
            endpoint = session.getAsyncRemote();
            break;
      }

      switch (payloadType) {
         case TEXT:
            if (endpoint instanceof RemoteEndpoint.Basic) {
               ((RemoteEndpoint.Basic) endpoint).sendText(message.getPayload().toString());
            } else {
               ((RemoteEndpoint.Async) endpoint).sendText(message.getPayload().toString());
            }
            break;
         case BINARY:
            if (endpoint instanceof RemoteEndpoint.Basic) {
               ((RemoteEndpoint.Basic) endpoint).sendBinary(ByteBuffer.wrap(message.getPayload().toString().getBytes(Utils.getDefaultEncoding())));
            } else {
               ((RemoteEndpoint.Async) endpoint).sendBinary(ByteBuffer.wrap(message.getPayload().toString().getBytes(Utils.getDefaultEncoding())));
            }
            break;
         case PING:
            endpoint.sendPing(ByteBuffer.wrap(message.getPayload().toString().getBytes(Utils.getDefaultEncoding())));
            break;
      }

      return null;
   }

   /**
    * Represents web socket client endpoint.
    *
    * @author Jiří Sviták
    */
   @ClientEndpoint
   public class PerfCakeClientEndpoint {

      /**
       * Is called when a new web socket session is open.
       *
       * @param session
       *       Web socket session.
       */
      @OnOpen
      public void onOpen(final Session session) {
         if (logger.isTraceEnabled()) {
            logger.trace("Connected with session id: " + session.getId());
         }
         WebSocketSender.this.session = session;
      }

      /**
       * Receives incoming web socket messages.
       *
       * @param message
       *       Incomming message.
       * @param session
       *       Web socket session.
       */
      @OnMessage
      public void onMessage(final String message, final Session session) {
         if (logger.isTraceEnabled()) {
            logger.trace("Received message: " + message);
         }
      }

      /**
       * Is called when a web socket session is closing.
       *
       * @param session
       *       Web socket session.
       * @param closeReason
       *       The reason why a web socket has been closed, or why it is being asked to close
       */
      @OnClose
      public void onClose(final Session session, final CloseReason closeReason) {
         if (logger.isTraceEnabled()) {
            logger.trace(String.format("Session %s closed because of %s", session.getId(), closeReason));
         }
      }
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy