content: /*
   * 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.jms.client;
  
  import javax.jms.IllegalStateException;
  import java.util.Set;
  
  import org.apache.activemq.artemis.utils.collections.ConcurrentHashSet;
  
  /**
   * Restricts what can be called on context passed in wrapped CompletionListener.
   */
  public class ThreadAwareContext {
  
     /**
      * Necessary in order to assert some methods ({@link javax.jms.JMSContext#stop()}
      * {@link javax.jms.JMSContext#close()} etc) are not getting called from within a
      * {@link javax.jms.CompletionListener}.
      *
      * @see ThreadAwareContext#assertNotMessageListenerThread()
      */
     private Thread completionListenerThread;
  
     /**
      * Use a set because JMSContext can create more than one JMSConsumer to receive asynchronously from different
      * destinations.
      */
     private final Set<Long> messageListenerThreads = new ConcurrentHashSet<>();
  
     /**
      * Sets current thread to the context
      * <p>
      * Meant to inform an JMSContext which is the thread that CANNOT call some of its methods.
      * </p>
      *
      * @param isCompletionListener indicating whether current thread is from CompletionListener or from MessageListener.
      */
     public void setCurrentThread(boolean isCompletionListener) {
        if (isCompletionListener) {
           completionListenerThread = Thread.currentThread();
        } else {
           messageListenerThreads.add(Thread.currentThread().getId());
        }
     }
  
     /**
      * Clear current thread from the context
      *
      * @param isCompletionListener indicating whether current thread is from CompletionListener or from MessageListener.
      */
     public void clearCurrentThread(boolean isCompletionListener) {
        if (isCompletionListener) {
           completionListenerThread = null;
        } else {
           messageListenerThreads.remove(Thread.currentThread().getId());
        }
     }
  
     /**
      * Asserts a {@link javax.jms.CompletionListener} is not calling from its own {@link javax.jms.JMSContext}.
      * <p>
      * Note that the code must work without any need for further synchronization, as there is the requirement that only
      * one CompletionListener be called at a time. In other words, CompletionListener calling is single-threaded.
      *
      * @see javax.jms.JMSContext#close()
      * @see javax.jms.JMSContext#stop()
      * @see javax.jms.JMSContext#commit()
      * @see javax.jms.JMSContext#rollback()
      */
     public void assertNotCompletionListenerThreadRuntime() {
        if (completionListenerThread == Thread.currentThread()) {
           throw ActiveMQJMSClientBundle.BUNDLE.callingMethodFromCompletionListenerRuntime();
        }
     }
  
     /**
      * Asserts a {@link javax.jms.CompletionListener} is not calling from its own {@link javax.jms.Connection} or from a
      * {@link javax.jms.MessageProducer} .
      * <p>
      * Note that the code must work without any need for further synchronization, as there is the requirement that only
      * one CompletionListener be called at a time. In other words, CompletionListener calling is single-threaded.
      *
      * @see javax.jms.Connection#close()
      * @see javax.jms.MessageProducer#close()
      */
     public void assertNotCompletionListenerThread() throws javax.jms.IllegalStateException {
        if (completionListenerThread == Thread.currentThread()) {
           throw ActiveMQJMSClientBundle.BUNDLE.callingMethodFromCompletionListener();
        }
     }
  
     /**
      * Asserts a {@link javax.jms.MessageListener} is not calling from its own {@link javax.jms.JMSContext}.
      * <p>
      * Note that the code must work without any need for further synchronization, as there is the requirement that only
      * one MessageListener be called at a time. In other words, MessageListener calling is single-threaded.
      *
      * @see javax.jms.JMSContext#close()
      * @see javax.jms.JMSContext#stop()
      */
     public void assertNotMessageListenerThreadRuntime() {
        if (messageListenerThreads.contains(Thread.currentThread().getId())) {
           throw ActiveMQJMSClientBundle.BUNDLE.callingMethodFromListenerRuntime();
        }
     }
  
     /**
      * Asserts a {@link javax.jms.MessageListener} is not calling from its own {@link javax.jms.Connection} or
      * {@link javax.jms.MessageConsumer}.
      * <p>
      * Note that the code must work without any need for further synchronization, as there is the requirement that only
      * one MessageListener be called at a time. In other words, MessageListener calling is single-threaded.
      *
      * @see javax.jms.Connection#close()
      * @see javax.jms.MessageConsumer#close()
      */
     public void assertNotMessageListenerThread() throws IllegalStateException {
        if (messageListenerThreads.contains(Thread.currentThread().getId())) {
           throw ActiveMQJMSClientBundle.BUNDLE.callingMethodFromListener();
        }
     }
  
  }
  