content: /*
   * $Id$
   * 
   * This file is part of the MoSKito software project
   * that is hosted at http://moskito.dev.java.net.
   * 
   * All MoSKito files are distributed under MIT License:
   * 
   * Copyright (c) 2006-2015 The MoSKito Project Team.
   * 
   * Permission is hereby granted, free of charge,
   * to any person obtaining a copy of this software and
   * associated documentation files (the "Software"), 
   * to deal in the Software without restriction, 
   * including without limitation the rights to use,
   * copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit 
   * persons to whom the Software is furnished to do so, 
   * subject to the following conditions:
   * 
   * The above copyright notice and this permission notice
   * shall be included in all copies 
   * or substantial portions of the Software.
   * 
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY
   * OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
   * LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 
   * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
   * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 
   * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
   * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   */
  package net.anotheria.moskito.core.registry;
  
  import net.anotheria.moskito.core.producers.IStatsProducer;
  import org.slf4j.Logger;
  import org.slf4j.LoggerFactory;
  
  import java.util.ArrayList;
  import java.util.Collection;
  import java.util.List;
  import java.util.concurrent.ConcurrentHashMap;
  import java.util.concurrent.ConcurrentMap;
  import java.util.concurrent.CopyOnWriteArrayList;
  
  /**
   * The ProducerRegistryImplementation is a singleton object, but for webapp-reloading issues it doesn't contain a
   * getInstance() method. Instead please use the ProducerRegistryFactory for instantiation.
   *
   * @author lrosenberg
   */
  public class ProducerRegistryImpl implements IProducerRegistry {
  
      /**
       * {@link Logger} instance.
       */
      private static final Logger LOGGER = LoggerFactory.getLogger(ProducerRegistryImpl.class);
  
      /**
       * The map in which the producers are stored.
       */
      private final ConcurrentMap<String, ProducerReference> registry = new ConcurrentHashMap<>();
  
      /**
       * The listeners list.
       */
      private final List<IProducerRegistryListener> listeners = new CopyOnWriteArrayList<IProducerRegistryListener>();
  
      /**
       * Creates the ProducerRegistryImpl singleton instance.
       */
      ProducerRegistryImpl() {
          reset();
      }
  
      @Override
      public void addListener(IProducerRegistryListener listener) {
          listeners.add(listener);
      }
  
      @Override
      public void removeListener(IProducerRegistryListener listener) {
          listeners.remove(listener);
      }
  
      @Override
      public Collection<IStatsProducer> getProducers() {
          List<IStatsProducer> ret = new ArrayList<>();
          for (ProducerReference r : getProducerReferences()) {
              if (r.get() != null)
                  ret.add(r.get());
          }
          return ret;
      }
  
      @Override
      public Collection<ProducerReference> getProducerReferences() {
          return registry.values();
      }
  
      @Override
      public IStatsProducer getProducer(String producerId) {
          if (producerId == null)
              throw new IllegalArgumentException("Null is not a valid producerId");
          ProducerReference ref = registry.get(producerId);
          return ref == null ? null : ref.get();
      }
  
      @Override
      public void registerProducer(IStatsProducer producer) {
          //null pointer exceptions in the toString method of the producer shouldn't crash here.
          String producerToString = null;
          try {
              producerToString = producer.toString();
          } catch (Exception e) {
              producerToString = "Illegal to string method: " + e.getMessage() + ", " + e.getClass();
          }
  
          LOGGER.info("Registry register producer: " + producer.getProducerId() + " / " + producerToString);
  
          ProducerReference previousRef = registry.putIfAbsent(producer.getProducerId(), new ProducerReference(producer));
  
          IStatsProducer previous = (previousRef == null) ? null : previousRef.get();
  
          if (previous != null) {
              LOGGER.info("Under this name a producer was already registered: " + previous);
          } else {
              for (IProducerRegistryListener listener : listeners) {
                  listener.notifyProducerRegistered(producer);
              }
          }
      }
  
  
      @Override
      public void unregisterProducer(IStatsProducer producer) {
          registry.remove(producer.getProducerId());
          for (IProducerRegistryListener listener : listeners) {
              listener.notifyProducerUnregistered(producer);
          }
      }
  
      /**
       * Resets the impl for unittests.
       */
      void reset() {
          cleanup(); // cleaning up all context before reseting producer registry instance
  
          listeners.clear();
          registry.clear();
  
          String junittest = System.getProperty("JUNITTEST");
          if (junittest != null && junittest.equalsIgnoreCase("true")) // preventing listener's initialization for JUnit run's
              return;
  
          addListener(new JMXBridgeListener());
  
      }
  
      /**
       * This method is primary used for unit tests.
       */
      public void cleanup() {
          ArrayList<ProducerReference> producerReferences = new ArrayList<ProducerReference>(registry.values());
          for (ProducerReference p : producerReferences) {
              try {
                  if (p.get() != null)
                      unregisterProducer(p.get());
              } catch (Exception e) {
                  LOGGER.warn("can't unregister producer " + p, e);
              }
          }
      }
  }
  