/*
 *  Copyright (c) 2012 Malhar, Inc.
 *  All Rights Reserved.
 */
package com.malhartech.lib.io;

import com.malhartech.api.ActivationListener;
import com.malhartech.api.Context.OperatorContext;
import com.malhartech.api.InputOperator;
import com.malhartech.util.CircularBuffer;
import javax.jms.JMSException;
import javax.jms.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * ActiveMQ input adapter operator, which consume data from ActiveMQ message bus.<p><br>
 *
 * It uses PUSH model to get message. When there is a message available in AMQ message bus,
 * onMessage() got called which buffer the message into a holding buffer. At the same time
 * Malhar Streaming Platform calls emitTuples() on this operator to process message from
 * the holding buffer through output port. Output port simply emit the message to next
 * connected operator.
 * This class can be used if operator has more than one output ports. If it has only one
 * output port it can conveniently derived from AbstractActiveMQSinglePortInputOperator class.
 *
 * <br>
 * Ports:<br>
 * <b>Input</b>: No input port<br>
 * <b>Output</b>: Can have any number of output ports<br>
 * <br>
 * Properties:<br>
 * <b>tuplesBlast</b>: Number of tuples emitted in each burst<br>
 * <b>bufferSize</b>: Size of holding buffer<br>
 * <br>
 * Compile time checks:<br>
 * Class derived from this has to implement the abstract method emitTuple() <br>
 * <br>
 * Run time checks:<br>
 * None<br>
 * <br>
 * Benchmarks:<br>
 * TBD<br>
 * <br>
 * @author Locknath Shil <locknath@malhar-inc.com>
 *
 */
public abstract class AbstractActiveMQInputOperator extends ActiveMQConsumerBase implements InputOperator, ActivationListener<OperatorContext>
{
  private static final Logger logger = LoggerFactory.getLogger(AbstractActiveMQInputOperator.class);
  protected static final int TUPLES_BLAST_DEFAULT = 10 * 1024; // 10k
  protected static final int BUFFER_SIZE_DEFAULT = 1024 * 1024; // 1M
  // Config parameters that user can set.-
  private int tuplesBlast = TUPLES_BLAST_DEFAULT;
  private int bufferSize = BUFFER_SIZE_DEFAULT;
  protected transient CircularBuffer<Message> holdingBuffer;

  /**
   * Any concrete class derived from AbstractActiveMQInputOperator has to implement this method
   * so that it knows what type of message it is going to send to Malhar in which output port.
   *
   * @param message
   */
  protected abstract void emitTuple(Message message);

  public int getTuplesBlast()
  {
    return tuplesBlast;
  }

  public void setTuplesBlast(int tuplesBlast)
  {
    this.tuplesBlast = tuplesBlast;
  }

  public int getBufferSize()
  {
    return bufferSize;
  }

  public void setBufferSize(int bufferSize)
  {
    this.bufferSize = bufferSize;
  }

  /**
   * Implement abstract method of ActiveMQConsumerBase
   */
  @Override
  protected final void emitMessage(Message message) throws JMSException
  {
    holdingBuffer.add(message);
  }

  /**
   * Implement Component Interface.
   *
   * @param context
   */
  @Override
  public void setup(OperatorConfiguration config)
  {
    holdingBuffer = new CircularBuffer<Message>(bufferSize);
  }

  /**
   * Implement Component Interface.
   */
  @Override
  public void teardown()
  {
  }

  /**
   * Implement Operator Interface.
   */
  @Override
  public void beginWindow(long windowId)
  {
  }

  /**
   * Implement Operator Interface.
   */
  @Override
  public void endWindow()
  {
  }

  /**
   * Implement ActivationListener Interface.
   */
  @Override
  public void activate(OperatorContext ctx)
  {
    try {
      setupConnection();
    }
    catch (JMSException ex) {
      logger.debug(ex.getLocalizedMessage());
    }
  }

  /**
   * Implement ActivationListener Interface.
   */
  @Override
  public void deactivate()
  {
    cleanup();
  }

  /**
   * Implement InputOperator Interface.
   * Pull message from temporary buffer and pass in emitTuple() in order to be processed/consumed
   * or pass to next operator.
   * To be more efficient emit all the tuples in buffer upto blastSize.
   * It also acknowledge that all messages have been received.
   */
  @Override
  public void emitTuples()
  {
    int messageCount = getTuplesBlast() < holdingBuffer.size() ? getTuplesBlast() : holdingBuffer.size();
    while (messageCount > 1) {
      emitTuple(holdingBuffer.pollUnsafe());
      messageCount--;
    }

    // Acknowledge all message with last message in buffer.
    if (messageCount == 1) {
      Message msg = holdingBuffer.pollUnsafe();
      emitTuple(msg);
      acknowledgeMessage(msg);
    }
  }
}

@@ -242,42 +242,47 @@
 ort 
-com.malhartech.util.CircularBuffer
+java.util.concurrent.ArrayBlockingQueue
 ;%0Aim
@@ -2130,30 +2130,34 @@
 ansient 
-CircularBuffer
+ArrayBlockingQueue
 %3CMessage
@@ -3118,22 +3118,26 @@
 new 
-CircularBuffer
+ArrayBlockingQueue
 %3CMes
@@ -4352,22 +4352,16 @@
 fer.poll
-Unsafe
 ());%0A   
@@ -4471,24 +4471,24 @@
 unt == 1) %7B%0A
+
       Messag
@@ -4517,14 +4517,8 @@
 poll
-Unsafe
 ();%0A

copy change from os