All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.soulwing.snmp.SnmpFactory Maven / Gradle / Ivy

Go to download

A simplified SNMP API for Java, inspired by Jürgen Schönwälder's Tnm extension for Tcl.

There is a newer version: 1.2.0
Show newest version
/*
 * tnm4j - Simplified SNMP API for Java
 * Copyright (C) 2012 Carl Harris, Jr
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
package org.soulwing.snmp;

import java.util.Iterator;
import java.util.ServiceLoader;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.soulwing.snmp.provider.SnmpProvider;

/**
 * A factory that produces contexts and listeners for SNMP.
 *
 * @author Carl Harris
 */
public class SnmpFactory {

  private static volatile SnmpFactory instance;

  private final Lock lock = new ReentrantLock();

  private final ServiceLoader loader = 
      ServiceLoader.load(SnmpProvider.class);
  
  private final AtomicBoolean closed = new AtomicBoolean();

  private final ConcurrentMap providerMap =
      new ConcurrentHashMap<>();

  private final ExecutorService executorService;
  private final ScheduledExecutorService scheduledExecutorService;
  private final ThreadFactory threadFactory;
  private final SnmpFactoryConfig factoryConfig;

  private SimpleSnmpTargetConfig defaultTargetConfig = 
      new SimpleSnmpTargetConfig();

  private SnmpFactory(ExecutorService executorService,
      ScheduledExecutorService scheduledExecutorService,
      ThreadFactory threadFactory, SnmpFactoryConfig factoryConfig) {
    this.executorService = executorService;
    this.scheduledExecutorService = scheduledExecutorService;
    this.threadFactory = threadFactory;
    this.factoryConfig = factoryConfig;
  }
  
  /**
   * Gets the singleton factory instance.
   * @return factory object
   */
  public static SnmpFactory getInstance() {
    return getInstance(
        new SnmpFactoryConfig(), new TrivialThreadFactory());
  }

  /**
   * Gets the singleton factory instance.
   * @param threadFactory thread factory that will be used to create threads
   *    as needed for components produced by this factory
   * @return factory object
   */
  public static SnmpFactory getInstance(ThreadFactory threadFactory) {
    return getInstance(
        new SnmpFactoryConfig(), new TrivialThreadFactory());
  }
  
  /**
   * Gets the singleton factory instance.
   * @param config factory configuration
   * @param threadFactory thread factory that will be used to create threads
   *    as needed for components produced by this factory
   * @return factory object
   */
  public static SnmpFactory getInstance(SnmpFactoryConfig config, 
      ThreadFactory threadFactory) {
    if (instance == null) {
      synchronized (SnmpFactory.class) {
        if (instance == null) {
          ExecutorService executorService = new ThreadPoolExecutor(
              config.getWorkerPoolSize(), config.getWorkerPoolSize(), 0L,
              TimeUnit.MILLISECONDS, new LinkedBlockingQueue(),
              threadFactory);
          ScheduledExecutorService scheduledExecutorService =
              new ScheduledThreadPoolExecutor(
                  config.getScheduledWorkerPoolSize(),
                  new ScheduledThreadFactory(threadFactory));
          instance = new SnmpFactory(executorService, scheduledExecutorService,
              threadFactory, config);
        }
      }
    }
    return instance;
  }

  private static class TrivialThreadFactory implements ThreadFactory {
    public Thread newThread(Runnable r) {
      return new Thread(r);
    }
  }

  private static final class ScheduledThreadFactory implements ThreadFactory {

    private final ThreadFactory delegate;

    public ScheduledThreadFactory(ThreadFactory delegate) {
      this.delegate = delegate;
    }

    @Override
    public Thread newThread(Runnable r) {
      final Thread thread = delegate.newThread(r);
      thread.setName("Scheduled " + thread.getName());
      thread.setDaemon(true);
      return thread;
    }

  }

  /**
   * Gets the executor service that should be used for short-lived tasks.
   * @return executor service
   */
  public ExecutorService getExecutorService() {
    assertNotClosed();
    return executorService;
  }

  /**
   * Gets the executor service that should be used for scheduled tasks.
   * @return executor service
   */
  public ScheduledExecutorService getScheduledExecutorService() {
    assertNotClosed();
    return scheduledExecutorService;
  }
  
  /**
   * Gets the thread factory that should be used to create threads for long
   * running tasks.
   * @return thread factory
   */
  public ThreadFactory getThreadFactory() {
    assertNotClosed();
    return threadFactory;
  }

  /**
   * Gets the factory configuration associated with this instance.
   * @return factory config
   */
  public SnmpFactoryConfig getFactoryConfig() {
    return factoryConfig;
  }

  /**
   * Closes this factory, releasing any resources it might be holding.
   * @throws InterruptedException
   */
  public void close() throws InterruptedException {
    if (!closed.compareAndSet(false, true)) return;
    shutDownProviders();
    shutDownExecutor(executorService);
    shutDownExecutor(scheduledExecutorService);
    if (Thread.interrupted()) {
      throw new InterruptedException();
    }
  }

  private void shutDownProviders() {
    for (SnmpProvider provider : providerMap.values()) {
      provider.close();
    }
    providerMap.clear();
  }

  private void shutDownExecutor(ExecutorService executorService) {
    try {
      executorService.shutdownNow();
      executorService.awaitTermination(defaultTargetConfig.getTimeout(),
          TimeUnit.MILLISECONDS);
    }
    catch (InterruptedException ex) {
      Thread.currentThread().interrupt();
    }
    catch (IllegalStateException ex) {
      assert true;  // it's okay -- probably a ManagedExecutorService
    }
  }

  /**
   * Gets the default configuration that will be used for new context
   * instances created by this factory.
   * @return configuration
   */
  public SimpleSnmpTargetConfig getDefaultTargetConfig() {
    return defaultTargetConfig;
  }

  /**
   * Sets the default configuration that will be used for new context
   * instances created by this factory.
   * @param config the value to set
   */
  public void setDefaultTargetConfig(SimpleSnmpTargetConfig config) {
    this.defaultTargetConfig = config;
  }

  /**
   * Gets a new SNMPv2c context using the first available provider, default
   * MIB, and the factory's default configuration. 
   * @param target target agent
   * @return SNMP context object
   */
  public SnmpContext newContext(SnmpTarget target) {
    return newContext(target, MibFactory.getInstance().newMib(),
        defaultTargetConfig, null);
  }

  /**
   * Gets a new SNMPv2c context using the first available provider and the
   * factory's default configuration.
   * @param target target agent
   * @param mib MIB that will be passed into the context
   * @return SNMP context object
   */
  public SnmpContext newContext(SnmpTarget target, Mib mib) {
    return newContext(target, mib, defaultTargetConfig, null);
  }

  /**
   * Gets a new SNMPv2c context using the first available provider.
   * @param target target agent
   * @param config SNMP configuration for the context
   * @return SNMP context object
   */
  public SnmpContext newContext(SnmpTarget target, 
      SnmpTargetConfig config) {
    return newContext(target, MibFactory.getInstance().newMib(), config, null);
  }

  /**
   * Gets a new SNMPv2c context using the named provider.
   * @param target target agent
   * @param mib MIB that will be passed into the context
   * @param config SNMP configuration for the context
   * @param providerName name of the desired provider
   * @return SNMP context object
   * @throws ProviderNotFoundException if the named provider cannot be
   *    found on the class path
   */
  public SnmpContext newContext(SnmpTarget target, Mib mib,
      SnmpTargetConfig config, String providerName) {
    assertNotClosed();
    return getProvider(providerName).newContext(target, config.clone(), mib);
  }

  /**
   * Creates a new listener that listens on the default notification port
   * with any local address, using the first available provider.
   * @param mib MIB that will be passed into the listener
   * @return SNMP notification listener
   */
  public SnmpListener newListener(Mib mib) {
    return newListener(null, SnmpDefaults.NOTIFICATION_PORT, mib, null);
  }

  /**
   * Creates a new listener that listens on any local address using the
   * first available provider.
   * @param port port on which to listen
   * @param mib MIB that will be passed into the listener
   * @return SNMP notification listener
   */
  public SnmpListener newListener(int port, Mib mib) {
    return newListener(null, port, mib, null);
  }

  /**
   * Creates a new listener using the first available provider.
   * @param address local address on which to listen or {@code null} to bind to
   *    any local address
   * @param port port on which to listen
   * @param mib MIB that will be passed into the listener
   * @return SNMP notification listener
   */
  public SnmpListener newListener(String address, int port, Mib mib) {
    return newListener(address, port, mib, null);
  }

  /**
   * Creates a new listener using the named provider.
   * @param address local address on which to listen or {@code null} to bind to
   *    any local address
   * @param port port on which to listen
   * @param mib MIB that will be passed into the listener
   * @param providerName name of the desired provider or {@code null} to
   *    use first available provider
   * @return SNMP notification listener
   */
  public SnmpListener newListener(String address, int port, Mib mib,
      String providerName) {
    assertNotClosed();
    return getProvider(providerName).newListener(address, port, mib);
  }

  /**
   * Gets a named provider instance (which may have been previously cached)
   * @param providerName provider name or {@code null} to find the first
   *    available provider
   * @return provider object
   * @throws ProviderNotFoundException if the named provider cannot be
   *    found by the {@link ServiceLoader} (or if no provider can be found
   *    when the specified name is {@code null})
   */
  private SnmpProvider getProvider(String providerName) {
    SnmpProvider provider = null;
    if (!providerMap.isEmpty()) {
      provider = providerName != null ?
          providerMap.get(providerName) : providerMap.values().iterator().next();
    }
    if (provider == null) {
      lock.lock();
      try {
        provider = findProvider(providerName);
        provider.init(factoryConfig);
        providerMap.put(provider.getName(), provider);
      }
      finally {
        lock.unlock();
      }
    }
    return provider;
  }

  /**
   * Finds a named provider
   * @param providerName provider name or {@code null} to find the first
   *    available provider
   * @return provider object
   * @throws ProviderNotFoundException if the named provider cannot be
   *    found by the {@link ServiceLoader} (or if no provider can be found, 
   *    when the specified name is {@code null}
   */
  private SnmpProvider findProvider(String providerName) {
    Iterator i = loader.iterator();
    while (i.hasNext()) {
      SnmpProvider provider = i.next();
      if (providerName == null 
          || provider.getName().equalsIgnoreCase(providerName)) {
        return provider;
      }
    }
    throw new ProviderNotFoundException(providerName);
  }

  private void assertNotClosed() {
    if (closed.get()) {
      throw new IllegalStateException("factory has been closed");
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy