/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.apache.activemq.artemis.tests.integration.jms.server.management;

import javax.jms.QueueConnection;
import javax.jms.QueueSession;
import javax.jms.Session;

import org.apache.activemq.artemis.api.core.TransportConfiguration;
import org.apache.activemq.artemis.api.core.client.ActiveMQClient;
import org.apache.activemq.artemis.api.core.management.ResourceNames;
import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient;
import org.apache.activemq.artemis.api.jms.JMSFactoryType;
import org.apache.activemq.artemis.api.jms.management.JMSServerControl;
import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQConnectionFactory;
import org.apache.activemq.artemis.jms.client.ActiveMQQueue;
import org.apache.activemq.artemis.jms.client.ActiveMQQueueConnectionFactory;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

public class JMSServerControlUsingJMSTest extends JMSServerControlTest {

   // Constants -----------------------------------------------------

   // Attributes ----------------------------------------------------

   private QueueConnection connection;

   private QueueSession session;

   // Static --------------------------------------------------------

   private static String[] toStringArray(final Object[] res) {
      String[] names = new String[res.length];
      for (int i = 0; i < res.length; i++) {
         names[i] = res[i].toString();
      }
      return names;
   }

   // The JMS test won't support the server being restarted, hence we have to do a slight different test on that case
   @Override
   @Test
   public void testCreateConnectionFactory_CompleteList() throws Exception {
      JMSServerControl control = createManagementControl();
      control.createConnectionFactory("test", //name
                                      true, // ha
                                      false, // useDiscovery
                                      1, // cfType
                                      "invm", // connectorNames
                                      "tst", // jndiBindins
                                      "tst", // clientID
                                      1, // clientFailureCheckPeriod
                                      1,  // connectionTTL
                                      1, // callTimeout
                                      1, // callFailoverTimeout
                                      1, // minLargeMessageSize
                                      true, // compressLargeMessages
                                      1, // consumerWindowSize
                                      1, // consumerMaxRate
                                      1, // confirmationWindowSize
                                      1, // ProducerWindowSize
                                      1, // producerMaxRate
                                      true, // blockOnACK
                                      true, // blockOnDurableSend
                                      true, // blockOnNonDurableSend
                                      true, // autoGroup
                                      true, // preACK
                                      ActiveMQClient.DEFAULT_CONNECTION_LOAD_BALANCING_POLICY_CLASS_NAME, // loadBalancingClassName
                                      1, // transactionBatchSize
                                      1, // dupsOKBatchSize
                                      true, // useGlobalPools
                                      1, // scheduleThreadPoolSize
                                      1, // threadPoolMaxSize
                                      1, // retryInterval
                                      1, // retryIntervalMultiplier
                                      1, // maxRetryInterval
                                      1, // reconnectAttempts
                                      true, // failoverOnInitialConnection
                                      "tst"); // groupID

      ActiveMQQueueConnectionFactory cf = (ActiveMQQueueConnectionFactory) context.lookup("tst");

      Assert.assertEquals(true, cf.isHA());
      Assert.assertEquals("tst", cf.getClientID());
      Assert.assertEquals(1, cf.getClientFailureCheckPeriod());
      Assert.assertEquals(1, cf.getConnectionTTL());
      Assert.assertEquals(1, cf.getCallTimeout());
      Assert.assertEquals(1, cf.getCallFailoverTimeout());
      Assert.assertEquals(1, cf.getMinLargeMessageSize());
      Assert.assertEquals(true, cf.isCompressLargeMessage());
      Assert.assertEquals(1, cf.getConsumerWindowSize());
      Assert.assertEquals(1, cf.getConfirmationWindowSize());
      Assert.assertEquals(1, cf.getProducerWindowSize());
      Assert.assertEquals(1, cf.getProducerMaxRate());
      Assert.assertEquals(true, cf.isBlockOnAcknowledge());
      Assert.assertEquals(true, cf.isBlockOnDurableSend());
      Assert.assertEquals(true, cf.isBlockOnNonDurableSend());
      Assert.assertEquals(true, cf.isAutoGroup());
      Assert.assertEquals(true, cf.isPreAcknowledge());
      Assert.assertEquals(ActiveMQClient.DEFAULT_CONNECTION_LOAD_BALANCING_POLICY_CLASS_NAME, cf.getConnectionLoadBalancingPolicyClassName());
      Assert.assertEquals(1, cf.getTransactionBatchSize());
      Assert.assertEquals(1, cf.getDupsOKBatchSize());
      Assert.assertEquals(true, cf.isUseGlobalPools());
      Assert.assertEquals(1, cf.getScheduledThreadPoolMaxSize());
      Assert.assertEquals(1, cf.getThreadPoolMaxSize());
      Assert.assertEquals(1, cf.getRetryInterval());
      Assert.assertEquals(1.0, cf.getRetryIntervalMultiplier(), 0.000001);
      Assert.assertEquals(1, cf.getMaxRetryInterval());
      Assert.assertEquals(1, cf.getReconnectAttempts());
      Assert.assertEquals(true, cf.isFailoverOnInitialConnection());
      Assert.assertEquals("tst", cf.getGroupID());

   }
   // Constructors --------------------------------------------------

   // JMSServerControlTest overrides --------------------------------
   @Override
   protected int getNumberOfConsumers() {
      return 1;
   }

   @Override
   @Before
   public void setUp() throws Exception {
      super.setUp();

      ActiveMQConnectionFactory cf = ActiveMQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, new TransportConfiguration(InVMConnectorFactory.class.getName()));
      connection = cf.createQueueConnection();
      session = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
      connection.start();
   }

   @Override
   protected JMSServerControl createManagementControl() throws Exception {
      ActiveMQQueue managementQueue = (ActiveMQQueue) ActiveMQJMSClient.createQueue("activemq.management");
      final JMSMessagingProxy proxy = new JMSMessagingProxy(session, managementQueue, ResourceNames.JMS_SERVER);

      return new JMSServerControl() {

         @Override
         public boolean closeConnectionsForAddress(final String ipAddress) throws Exception {
            return (Boolean) proxy.invokeOperation("closeConnectionsForAddress", ipAddress);
         }

         @Override
         public boolean closeConsumerConnectionsForAddress(final String address) throws Exception {
            return (Boolean) proxy.invokeOperation("closeConsumerConnectionsForAddress", address);
         }

         @Override
         public boolean closeConnectionsForUser(final String userName) throws Exception {
            return (Boolean) proxy.invokeOperation("closeConnectionsForUser", userName);
         }

         @Override
         public boolean createQueue(final String name) throws Exception {
            return (Boolean) proxy.invokeOperation("createQueue", name);
         }

         @Override
         public boolean createQueue(String name, String jndiBindings, String selector) throws Exception {
            return (Boolean) proxy.invokeOperation("createQueue", name, jndiBindings, selector);
         }

         @Override
         public boolean createQueue(String name,
                                    String jndiBindings,
                                    String selector,
                                    boolean durable) throws Exception {
            return (Boolean) proxy.invokeOperation("createQueue", name, jndiBindings, selector, durable);
         }

         @Override
         public boolean createTopic(final String name) throws Exception {
            return (Boolean) proxy.invokeOperation("createTopic", name);
         }

         @Override
         public void destroyConnectionFactory(final String name) throws Exception {
            proxy.invokeOperation("destroyConnectionFactory", name);
         }

         @Override
         public boolean destroyQueue(final String name) throws Exception {
            return (Boolean) proxy.invokeOperation("destroyQueue", name);
         }

         @Override
         public boolean destroyQueue(String name, boolean removeConsumers) throws Exception {
            return (Boolean) proxy.invokeOperation("destroyQueue", name, removeConsumers);
         }

         @Override
         public boolean destroyTopic(final String name) throws Exception {
            return (Boolean) proxy.invokeOperation("destroyTopic", name);
         }

         @Override
         public boolean destroyTopic(final String name, boolean removeConsumers) throws Exception {
            return (Boolean) proxy.invokeOperation("destroyTopic", name, removeConsumers);
         }

         @Override
         public String getVersion() {
            return (String) proxy.retrieveAttributeValue("version");
         }

         @Override
         public boolean isStarted() {
            return (Boolean) proxy.retrieveAttributeValue("started");
         }

         @Override
         public String[] getQueueNames() {
            return JMSServerControlUsingJMSTest.toStringArray((Object[]) proxy.retrieveAttributeValue("queueNames"));
         }

         @Override
         public String[] getTopicNames() {
            return JMSServerControlUsingJMSTest.toStringArray((Object[]) proxy.retrieveAttributeValue("topicNames"));
         }

         @Override
         public String[] getConnectionFactoryNames() {
            return JMSServerControlUsingJMSTest.toStringArray((Object[]) proxy.retrieveAttributeValue("connectionFactoryNames"));
         }

         @Override
         public String getNodeID() {
            return null;
         }

         @Override
         public String[] listConnectionIDs() throws Exception {
            return (String[]) proxy.invokeOperation("listConnectionIDs");
         }

         @Override
         public String listConnectionsAsJSON() throws Exception {
            return (String) proxy.invokeOperation("listConnectionsAsJSON");
         }

         @Override
         public String listConsumersAsJSON(String connectionID) throws Exception {
            return (String) proxy.invokeOperation("listConsumersAsJSON", connectionID);
         }

         @Override
         public String[] listRemoteAddresses() throws Exception {
            return (String[]) proxy.invokeOperation("listRemoteAddresses");
         }

         @Override
         public String[] listRemoteAddresses(final String ipAddress) throws Exception {
            return (String[]) proxy.invokeOperation("listRemoteAddresses", ipAddress);
         }

         @Override
         public String[] listSessions(final String connectionID) throws Exception {
            return (String[]) proxy.invokeOperation("listSessions", connectionID);
         }

         @Override
         public boolean createQueue(String name, String jndiBinding) throws Exception {
            return (Boolean) proxy.invokeOperation("createQueue", name, jndiBinding);
         }

         @Override
         public boolean createTopic(String name, String jndiBinding) throws Exception {
            return (Boolean) proxy.invokeOperation("createTopic", name, jndiBinding);
         }

         @Override
         public String[] listTargetDestinations(String sessionID) throws Exception {
            return null;
         }

         @Override
         public String getLastSentMessageID(String sessionID, String address) throws Exception {
            return null;
         }

         @Override
         public String getSessionCreationTime(String sessionID) throws Exception {
            return (String) proxy.invokeOperation("getSessionCreationTime", sessionID);
         }

         @Override
         public String listSessionsAsJSON(String connectionID) throws Exception {
            return (String) proxy.invokeOperation("listSessionsAsJSON", connectionID);
         }

         @Override
         public String listPreparedTransactionDetailsAsJSON() throws Exception {
            return (String) proxy.invokeOperation("listPreparedTransactionDetailsAsJSON");
         }

         @Override
         public String listNetworkTopology() throws Exception {
            return null;
         }

         @Override
         public String listPreparedTransactionDetailsAsHTML() throws Exception {
            return (String) proxy.invokeOperation("listPreparedTransactionDetailsAsHTML");
         }

         @Override
         public void createConnectionFactory(String name,
                                             boolean ha,
                                             boolean useDiscovery,
                                             int cfType,
                                             String[] connectorNames,
                                             Object[] bindings) throws Exception {
            proxy.invokeOperation("createConnectionFactory", name, ha, useDiscovery, cfType, connectorNames, bindings);

         }

         @Override
         public void createConnectionFactory(String name,
                                             boolean ha,
                                             boolean useDiscovery,
                                             int cfType,
                                             String connectors,
                                             String jndiBindings) throws Exception {
            proxy.invokeOperation("createConnectionFactory", name, ha, useDiscovery, cfType, connectors, jndiBindings);
         }

         @Override
         public String listAllConsumersAsJSON() throws Exception {
            return (String) proxy.invokeOperation("listAllConsumersAsJSON");
         }

         @Override
         public void createConnectionFactory(String name,
                                             boolean ha,
                                             boolean useDiscovery,
                                             int cfType,
                                             String[] connectors,
                                             String[] jndiBindings,
                                             String clientID,
                                             long clientFailureCheckPeriod,
                                             long connectionTTL,
                                             long callTimeout,
                                             long callFailoverTimeout,
                                             int minLargeMessageSize,
                                             boolean compressLargeMessages,
                                             int consumerWindowSize,
                                             int consumerMaxRate,
                                             int confirmationWindowSize,
                                             int producerWindowSize,
                                             int producerMaxRate,
                                             boolean blockOnAcknowledge,
                                             boolean blockOnDurableSend,
                                             boolean blockOnNonDurableSend,
                                             boolean autoGroup,
                                             boolean preAcknowledge,
                                             String loadBalancingPolicyClassName,
                                             int transactionBatchSize,
                                             int dupsOKBatchSize,
                                             boolean useGlobalPools,
                                             int scheduledThreadPoolMaxSize,
                                             int threadPoolMaxSize,
                                             long retryInterval,
                                             double retryIntervalMultiplier,
                                             long maxRetryInterval,
                                             int reconnectAttempts,
                                             boolean failoverOnInitialConnection,
                                             String groupId) throws Exception {
            proxy.invokeOperation("createConnectionFactory", name, ha, useDiscovery, cfType, connectors, jndiBindings, clientID, clientFailureCheckPeriod, connectionTTL, callTimeout, callFailoverTimeout, minLargeMessageSize, compressLargeMessages, consumerWindowSize, consumerMaxRate, confirmationWindowSize, producerWindowSize, producerMaxRate, blockOnAcknowledge, blockOnDurableSend, blockOnNonDurableSend, autoGroup, preAcknowledge, loadBalancingPolicyClassName, transactionBatchSize, dupsOKBatchSize, useGlobalPools, scheduledThreadPoolMaxSize, threadPoolMaxSize, retryInterval, retryIntervalMultiplier, maxRetryInterval, reconnectAttempts, failoverOnInitialConnection, groupId);
         }

         @Override
         public void createConnectionFactory(String name,
                                             boolean ha,
                                             boolean useDiscovery,
                                             int cfType,
                                             String connectors,
                                             String jndiBindings,
                                             String clientID,
                                             long clientFailureCheckPeriod,
                                             long connectionTTL,
                                             long callTimeout,
                                             long callFailoverTimeout,
                                             int minLargeMessageSize,
                                             boolean compressLargeMessages,
                                             int consumerWindowSize,
                                             int consumerMaxRate,
                                             int confirmationWindowSize,
                                             int producerWindowSize,
                                             int producerMaxRate,
                                             boolean blockOnAcknowledge,
                                             boolean blockOnDurableSend,
                                             boolean blockOnNonDurableSend,
                                             boolean autoGroup,
                                             boolean preAcknowledge,
                                             String loadBalancingPolicyClassName,
                                             int transactionBatchSize,
                                             int dupsOKBatchSize,
                                             boolean useGlobalPools,
                                             int scheduledThreadPoolMaxSize,
                                             int threadPoolMaxSize,
                                             long retryInterval,
                                             double retryIntervalMultiplier,
                                             long maxRetryInterval,
                                             int reconnectAttempts,
                                             boolean failoverOnInitialConnection,
                                             String groupId) throws Exception {
            proxy.invokeOperation("createConnectionFactory", name, ha, useDiscovery, cfType, connectors, jndiBindings, clientID, clientFailureCheckPeriod, connectionTTL, callTimeout, callFailoverTimeout, minLargeMessageSize, compressLargeMessages, consumerWindowSize, consumerMaxRate, confirmationWindowSize, producerWindowSize, producerMaxRate, blockOnAcknowledge, blockOnDurableSend, blockOnNonDurableSend, autoGroup, preAcknowledge, loadBalancingPolicyClassName, transactionBatchSize, dupsOKBatchSize, useGlobalPools, scheduledThreadPoolMaxSize, threadPoolMaxSize, retryInterval, retryIntervalMultiplier, maxRetryInterval, reconnectAttempts, failoverOnInitialConnection, groupId);
         }

         @Override
         public String closeConnectionWithClientID(String clientID) throws Exception {
            return (String) proxy.invokeOperation("closeConnectionWithClientID", clientID);
         }

      };
   }
}
