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.plugin;
  
  import java.util.concurrent.ConcurrentLinkedQueue;
  import java.util.concurrent.locks.ReentrantReadWriteLock;
  import java.util.regex.Pattern;
  
  import javax.management.ObjectName;
  
  import org.apache.activemq.broker.Broker;
  import org.apache.activemq.broker.BrokerFilter;
  import org.apache.activemq.broker.ConnectionContext;
  import org.apache.activemq.broker.region.Destination;
  import org.apache.activemq.command.ActiveMQDestination;
  import org.apache.activemq.command.ConnectionInfo;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  public class AbstractRuntimeConfigurationBroker extends BrokerFilter {
  
      public static final Logger LOG = LoggerFactory.getLogger(AbstractRuntimeConfigurationBroker.class);
      protected final ReentrantReadWriteLock addDestinationBarrier = new ReentrantReadWriteLock();
      protected final ReentrantReadWriteLock addConnectionBarrier = new ReentrantReadWriteLock();
      protected Runnable monitorTask;
      protected ConcurrentLinkedQueue<Runnable> addDestinationWork = new ConcurrentLinkedQueue<Runnable>();
      protected ConcurrentLinkedQueue<Runnable> addConnectionWork = new ConcurrentLinkedQueue<Runnable>();
      protected ObjectName objectName;
      protected String infoString;
  
      public AbstractRuntimeConfigurationBroker(Broker next) {
          super(next);
      }
  
      @Override
      public void start() throws Exception {
          super.start();
      }
  
      @Override
      public void stop() throws Exception {
          if (monitorTask != null) {
              try {
                  this.getBrokerService().getScheduler().cancel(monitorTask);
              } catch (Exception letsNotStopStop) {
                  LOG.warn("Failed to cancel config monitor task", letsNotStopStop);
              }
          }
          unregisterMbean();
          super.stop();
      }
  
      protected void registerMbean() {
  
      }
  
      protected void unregisterMbean() {
  
      }
  
      // modification to virtual destinations interceptor needs exclusive access to destination add
      @Override
      public Destination addDestination(ConnectionContext context, ActiveMQDestination destination, boolean createIfTemporary) throws Exception {
          Runnable work = addDestinationWork.poll();
          if (work != null) {
              addDestinationBarrier.writeLock().lockInterruptibly();
              try {
                  do {
                      work.run();
                      work = addDestinationWork.poll();
                  } while (work != null);
                  return super.addDestination(context, destination, createIfTemporary);
              } finally {
                  addDestinationBarrier.writeLock().unlock();
              }
          } else {
              addDestinationBarrier.readLock().lockInterruptibly();
              try {
                  return super.addDestination(context, destination, createIfTemporary);
              } finally {
                  addDestinationBarrier.readLock().unlock();
              }
          }
      }
  
      // modification to authentication plugin needs exclusive access to connection add
      @Override
      public void addConnection(ConnectionContext context, ConnectionInfo info) throws Exception {
          Runnable work = addConnectionWork.poll();
          if (work != null) {
              addConnectionBarrier.writeLock().lockInterruptibly();
              try {
                  do {
                      work.run();
                      work = addConnectionWork.poll();
                  } while (work != null);
                  super.addConnection(context, info);
              } finally {
                  addConnectionBarrier.writeLock().unlock();
              }
          } else {
              addConnectionBarrier.readLock().lockInterruptibly();
              try {
                  super.addConnection(context, info);
              } finally {
                  addConnectionBarrier.readLock().unlock();
              }
          }
      }
  
      /**
       * Apply the destination work immediately instead of waiting for
       * a connection add or destination add
       *
       * @throws Exception
       */
      protected void applyDestinationWork() throws Exception {
          Runnable work = addDestinationWork.poll();
          if (work != null) {
              addDestinationBarrier.writeLock().lockInterruptibly();
              try {
                  do {
                      work.run();
                      work = addDestinationWork.poll();
                  } while (work != null);
              } finally {
                  addDestinationBarrier.writeLock().unlock();
              }
          }
      }
  
      public void debug(String s) {
          LOG.debug(s);
      }
  
      public void info(String s) {
          LOG.info(filterPasswords(s));
          if (infoString != null) {
              infoString += s;
              infoString += ";";
          }
      }
  
      public void info(String s, Throwable t) {
          LOG.info(filterPasswords(s), t);
          if (infoString != null) {
              infoString += s;
              infoString += ", " + t;
              infoString += ";";
          }
      }
  
      Pattern matchPassword = Pattern.compile("password=.*,");
      protected String filterPasswords(Object toEscape) {
          return matchPassword.matcher(toEscape.toString()).replaceAll("password=???,");
      }
  
  }