Package org.infinispan.client.hotrod.impl.operations

Source Code of org.infinispan.client.hotrod.impl.operations.AddClientListenerOperation

package org.infinispan.client.hotrod.impl.operations;

import org.infinispan.client.hotrod.Flag;
import org.infinispan.client.hotrod.annotation.ClientListener;
import org.infinispan.client.hotrod.event.ClientEvent;
import org.infinispan.client.hotrod.event.ClientListenerNotifier;
import org.infinispan.client.hotrod.impl.protocol.Codec;
import org.infinispan.commons.util.Either;
import org.infinispan.client.hotrod.impl.protocol.HeaderParams;
import org.infinispan.client.hotrod.impl.transport.Transport;
import org.infinispan.client.hotrod.impl.transport.TransportFactory;
import org.infinispan.client.hotrod.logging.Log;
import org.infinispan.client.hotrod.logging.LogFactory;
import org.infinispan.commons.util.ReflectionUtil;

import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;

/**
* @author Galder Zamarreño
*/
public class AddClientListenerOperation extends RetryOnFailureOperation<Short> {

   private static final Log log = LogFactory.getLog(AddClientListenerOperation.class, Log.class);

   public final byte[] listenerId;

   /**
    * Decicated transport instance for adding client listener. This transport
    * is used to send events back to client and it's only released when the
    * client listener is removed.
    */
   private Transport dedicatedTransport;

   private final ClientListenerNotifier listenerNotifier;
   public final Object listener;
   public final byte[][] filterFactoryParams;
   public final byte[][] converterFactoryParams;

   protected AddClientListenerOperation(Codec codec, TransportFactory transportFactory,
         byte[] cacheName, AtomicInteger topologyId, Flag[] flags,
         ClientListenerNotifier listenerNotifier, Object listener,
         byte[][] filterFactoryParams, byte[][] converterFactoryParams) {
      super(codec, transportFactory, cacheName, topologyId, flags);
      this.listenerId = generateListenerId();
      this.listenerNotifier = listenerNotifier;
      this.listener = listener;
      this.filterFactoryParams = filterFactoryParams;
      this.converterFactoryParams = converterFactoryParams;
   }

   private byte[] generateListenerId() {
      UUID uuid = UUID.randomUUID();
      byte[] listenerId = new byte[16];
      ByteBuffer bb = ByteBuffer.wrap(listenerId);
      bb.putLong(uuid.getMostSignificantBits());
      bb.putLong(uuid.getLeastSignificantBits());
      return listenerId;
   }

   @Override
   protected Transport getTransport(int retryCount, Set<SocketAddress> failedServers) {
      this.dedicatedTransport = transportFactory.getTransport(failedServers, cacheName);
      return dedicatedTransport;
   }

   @Override
   protected void releaseTransport(Transport transport) {
      // Do not release transport instance, it's fully dedicated to events
   }

   public Transport getDedicatedTransport() {
      return dedicatedTransport;
   }

   @Override
   protected Short executeOperation(Transport transport) {
      ClientListener clientListener = extractClientListener();

      HeaderParams params = writeHeader(transport, ADD_CLIENT_LISTENER_REQUEST);
      transport.writeArray(listenerId);
      transport.writeByte((short)(clientListener.includeCurrentState() ? 1 : 0));

      writeNamedFactory(transport, clientListener.filterFactoryName(), filterFactoryParams);
      writeNamedFactory(transport, clientListener.converterFactoryName(), converterFactoryParams);

      transport.flush();

      listenerNotifier.addClientListener(this);
      Either<Short, ClientEvent> either;
      do {
         // Process state transfer related events or add listener response
         either = codec.readHeaderOrEvent(dedicatedTransport, params, listenerId, listenerNotifier.getMarshaller());
         switch(either.type()) {
            case LEFT:
               if (either.left() == NO_ERROR_STATUS)
                  listenerNotifier.startClientListener(listenerId);
               else // If error, remove it
                  listenerNotifier.removeClientListener(listenerId);
               break;
            case RIGHT:
               listenerNotifier.invokeEvent(listenerId, either.right());
               break;
         }
      } while (either.type() == Either.Type.RIGHT);

      return either.left();
   }

   private void writeNamedFactory(Transport transport, String factoryName, byte[][] params) {
      transport.writeString(factoryName);
      if (!factoryName.isEmpty()) {
         // A named factory was written, how many parameters?
         if (params != null) {
            transport.writeByte((short) params.length);
            for (byte[] param : params)
               transport.writeArray(param);
         } else {
            transport.writeByte((short) 0);
         }
      }
   }

   private ClientListener extractClientListener() {
      ClientListener l = ReflectionUtil.getAnnotation(listener.getClass(), ClientListener.class);
      if (l == null)
         throw log.missingClientListenerAnnotation(listener.getClass().getName());
      return l;
   }

}
TOP

Related Classes of org.infinispan.client.hotrod.impl.operations.AddClientListenerOperation

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.