Announcement Announcement Module
Collapse
No announcement yet.
SNMP4J in J2EE environment, Spring/CommonJ integration Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • SNMP4J in J2EE environment, Spring/CommonJ integration

    Hi,

    We are developing a J2EE application that uses the SNMP4J framework (to send SNMP commands and receive TRAP). Our platform is IBM Websphere Application Server 6.1.

    You can find information about SNMP4J on the official site:
    http://www.snmp4j.org/

    We use the following versions:
    SNMP4J 1.10.2
    Spring 2.5.6-SEC01

    J2EE application cannot use their own threads and timers inside the container. Snmp4J framework needs threads and timers but provides a ThreadFactory interface and a TimerFactory interface for integration purpose.
    http://www.snmp4j.org/doc/org/snmp4j...adFactory.html
    http://www.snmp4j.org/doc/org/snmp4j...erFactory.html

    We developed a Spring/CommonJ based ThreadFactory and a CommonJ based TimerFactory.

    We are posting the source of these implementation to provide a base if someone wants to integrate SNMP4J in a J2EE project, and to correct/enhance these implementations thanks to users comments/suggestions.


    ThreadFactory************************************************** ******************************************
    http://www.snmp4j.org/doc/org/snmp4j...adFactory.html
    http://www.snmp4j.org/doc/org/snmp4j...orkerTask.html

    As you can see from SNMP4J API doc, the ThreadFactory will produce WorkerTask which acts as an interface for Thread objects.

    We developed a ThreadFactory based on Spring TaskExecutor abstraction. This way this could be used with others J2EE executors (CommonJ (IBM WAS, BEA Weblogic,...), JCA (GlassFish, JBoss), ...).

    Our implementations wraps the submitted WorkerTask in an object that implements the SchedulingAwareRunnable interface. When the run method is called, the wrapped WorkerTask is submitted to the executor. Calls to others WorkTask interface methods are forwarded to the wrapped WorkerTask.
    In a WAS environment, the TaskExecutor would be a WorkManagerTaskExecutor (using a WAS Workmanager (CommonJ)). Thanks to the SchedulingAwareRunnable interface, we will get rid of the "Thread hung" warnings in the WAS console for daemon threads.

    TaskExecutorThreadFactoryImpl:

    Code:
    package org.snmp4j.util.spring;
    
    import org.snmp4j.log.LogAdapter;
    import org.snmp4j.log.LogFactory;
    import org.snmp4j.util.ThreadFactory;
    import org.snmp4j.util.WorkerTask;
    import org.springframework.core.task.TaskExecutor;
    import org.springframework.util.Assert;
    
    /**
     * TreadFactory implementation based on Spring TaskExecutor.
     */
    public class TaskExecutorThreadFactoryImpl implements ThreadFactory {
    
    	/**
    	 * Logger.
    	 */
    	final static LogAdapter LOGGER = LogFactory
    			.getLogger(TaskExecutorThreadFactoryImpl.class);
    
    	/**
    	 * TaskExecutor.
    	 */
    	private TaskExecutor taskExecutor;
    
    	/**
    	 * Set TaskExecutor.
    	 * 
    	 * @param taskExecutor
    	 *            a TaskExecutor.
    	 */
    	public void setTaskExecutor(TaskExecutor taskExecutor) {
    		this.taskExecutor = taskExecutor;
    	}
    
    	/**
    	 * Constructor.
    	 */
    	public TaskExecutorThreadFactoryImpl() {
    	}
    
    	/*
    	 * (without Javadoc)
    	 * 
    	 * @see org.snmp4j.util.ThreadFactory#createWorkerThread(java.lang.String,
    	 *      org.snmp4j.util.WorkerTask, boolean)
    	 */
    	public WorkerTask createWorkerThread(String name, WorkerTask task,
    			boolean daemon) {
    		LOGGER.debug("Creating WorkerThread: " + name + " daemon: " + daemon);
    		return new TaskExecutorWorkerTaskImpl(taskExecutor, name, task,
    				daemon);
    	}
    
    	/**
    	 * Initialization.
    	 */
    	public void init() {
    		Assert.notNull(taskExecutor, "taskExecutor is required.");
    	}
    
    }
    TaskExecutorWorkerTaskImpl:

    Code:
    package org.snmp4j.util.spring;
    
    import org.snmp4j.log.LogAdapter;
    import org.snmp4j.log.LogFactory;
    import org.snmp4j.util.WorkerTask;
    import org.springframework.core.task.TaskExecutor;
    import org.springframework.scheduling.SchedulingAwareRunnable;
    
    /**
     * WorkerTask implementation based on Spring TaskExecutor.
     */
    public class TaskExecutorWorkerTaskImpl implements WorkerTask {
    
    	/**
    	 * Logger.
    	 */
    	final static LogAdapter LOGGER = LogFactory
    			.getLogger(TaskExecutorWorkerTaskImpl.class);
    
    	/**
    	 * TaskExecutor.
    	 */
    	private TaskExecutor taskExecutor;
    
    	/**
    	 * Name.
    	 */
    	private String name;
    
    	/**
    	 * Worker task wrapper.
    	 */
    	private WorkerTaskWrapper workerTaskWrapper;
    
    	/**
    	 * Constructor.
    	 * 
    	 * @param taskExecutor
    	 *            a task executor.
    	 * @param name
    	 *            a name.
    	 * @param workerTask
    	 *            a worker task.
    	 * @param daemon
    	 *            true if daemon process, false otherwise.
    	 */
    	public TaskExecutorWorkerTaskImpl(TaskExecutor taskExecutor,
    			String name, WorkerTask workerTask, boolean daemon) {
    		this.taskExecutor = taskExecutor;
    		this.name = name;
    		this.workerTaskWrapper = new WorkerTaskWrapper(workerTask, daemon);
    	}
    
    	/*
    	 * (withoutJavadoc)
    	 * 
    	 * @see org.snmp4j.util.WorkerTask#interrupt()
    	 */
    	public void interrupt() {
    		LOGGER.debug("WorkerTask interrupt: " + this.name);
    		workerTaskWrapper.workerTask.interrupt();
    	}
    
    	/*
    	 * (withoutJavadoc)
    	 * 
    	 * @see org.snmp4j.util.WorkerTask#join()
    	 */
    	public void join() throws InterruptedException {
    		LOGGER.debug("WorkerTask join: " + this.name);
    		workerTaskWrapper.workerTask.join();
    	}
    
    	/*
    	 * (withoutJavadoc)
    	 * 
    	 * @see org.snmp4j.util.WorkerTask#terminate()
    	 */
    	public void terminate() {
    		LOGGER.debug("WorkerTask terminate: " + this.name);
    		workerTaskWrapper.workerTask.terminate();
    	}
    
    	/*
    	 * (withoutJavadoc)
    	 * 
    	 * @see java.lang.Runnable#run()
    	 */
    	public void run() {
    		LOGGER.debug("WorkerTask run: " + this.name);
    		taskExecutor.execute(workerTaskWrapper);
    	}
    
    	/**
    	 * Wrapper for WorkerTask.
    	 * 
    	 */
    	private class WorkerTaskWrapper implements SchedulingAwareRunnable {
    
    		/**
    		 * Worker task.
    		 */
    		private WorkerTask workerTask;
    
    		/**
    		 * True if daemon process, false otherwise.
    		 */
    		private boolean daemon;
    
    		/**
    		 * Constructor.
    		 * 
    		 * @param workerTask
    		 *            a worker task.
    		 * @param daemon
    		 *            true if daemon process, false otherwise.
    		 */
    		public WorkerTaskWrapper(WorkerTask workerTask, boolean daemon) {
    			this.workerTask = workerTask;
    			this.daemon = daemon;
    		}
    
    		/*
    		 * (without Javadoc)
    		 * 
    		 * @see java.lang.Runnable#run()
    		 */
    		public void run() {
    			workerTask.run();
    		}
    
    		/*
    		 * (without Javadoc)
    		 * 
    		 * @see org.springframework.scheduling.SchedulingAwareRunnable#isLongLived()
    		 */
    		public boolean isLongLived() {
    			return daemon;
    		}
    
    	}
    }
    Extract from applicationContext.xml for a J2EE/CommonJ environment:

    <bean id="taskExecutor"
    class=
    "org.springframework.scheduling.commonj.WorkManage rTaskExecutor"
    p:workManagerName="yourWorkManagerReferenceName"
    p:resourceRef="true" />

    <bean id="snmp4jThreadFactory"
    class=
    "org.snmp4j.util.spring.TaskExecutorThreadFactoryI mpl"
    init-method="init" p:taskExecutor-ref="taskExecutor" />

    You will need a work manager defined in your application server, and a
    reference defined in your web.xml for it.
    Last edited by jarodcanal; Mar 17th, 2010, 08:59 AM.

  • #2
    (continuing previous message)

    TimerFactory************************************************** ******************************************
    http://www.snmp4j.org/doc/org/snmp4j...erFactory.html
    http://www.snmp4j.org/doc/org/snmp4j...mmonTimer.html

    As you can see from SNMP4J API doc, the TimerFactory will produce CommonTimer which acts as an interface for java.util.Timer objects.

    We developed a TimerFactory based on CommonJ TimerManager.
    It should be easy to make an implementation based on Spring TaskScheduler abstraction, but since we cannot upgrade right now to Spring 3.0.x, we chose a CommonJ implementation.

    Our implementations wraps the submitted java.util.TimerTask in an object that implements the TimerListener interface (a CommonJ interface for Runnable objects). The wrapped java.util.TimerTask are scheduled against a TimerManager. Our implementation keeps track of submitted java.util.TimerTask to prevent rescheduling; it also keeps track of generated CommonJ Timers to cancel them when cancelling the CommonTimer.
    Java_____________/___SNMP4J__________/___CommonJ
    java.util.TimerTask_/___java.util.TimerTask_/___commonj.timers.TimerListener+commonj.timers.Tim er
    java.util.Timer_____/___CommonTimer_____/___commonj.timers.TimerManager

    TimerTask objects that are just executed once are removed from tracking after execution.
    TimerTask objects that are going to repeat are discarded when CommonTimer is cancelled.

    Known limitation: this CommonJ TimerFactory will work while the "scheduledExecutionTime" method of submitted java.util.TimerTask is not used (i.e. while it is not called from "run" method in TimerTask as it is supposed to be).

    Any help with the synchronized statements would be great (since it can probably be better).

    TimerManagerTimerFactoryImpl:

    Code:
    package org.snmp4j.util.commonj;
    
    import org.snmp4j.log.LogAdapter;
    import org.snmp4j.log.LogFactory;
    import org.snmp4j.util.CommonTimer;
    import org.snmp4j.util.TimerFactory;
    
    import commonj.timers.TimerManager;
    
    /**
     * TimerFactory implementation based on CommonJ TimerManager.
     */
    public class TimerManagerTimerFactoryImpl implements TimerFactory {
    
    	/**
    	 * Logger.
    	 */
    	final static LogAdapter LOGGER = LogFactory
    			.getLogger(TimerManagerTimerFactoryImpl.class);
    
    	/**
    	 * TimerManager.
    	 */
    	private final TimerManager timerManager;
    
    	/**
    	 * Constructor.
    	 * 
    	 * @param timerManager
    	 *            a TimerManager.
    	 */
    	public TimerManagerTimerFactoryImpl(TimerManager timerManager) {
    		if (timerManager == null) {
    			throw new NullPointerException("TimerManager is required");
    		}
    		this.timerManager = timerManager;
    	}
    
    	/*
    	 * (without Javadoc)
    	 * 
    	 * @see org.snmp4j.util.TimerFactory#createTimer()
    	 */
    	public CommonTimer createTimer() {
    		LOGGER.debug("Creating Timer");
    		return new TimerManagerCommonTimerImpl(timerManager);
    	}
    
    }

    Comment


    • #3
      (continuing previous message)

      TimerManagerCommonTimerImpl:

      Code:
      package org.snmp4j.util.commonj;
      
      import java.util.Collections;
      import java.util.Date;
      import java.util.HashSet;
      import java.util.Set;
      import java.util.TimerTask;
      
      import org.snmp4j.log.LogAdapter;
      import org.snmp4j.log.LogFactory;
      import org.snmp4j.util.CommonTimer;
      
      import commonj.timers.Timer;
      import commonj.timers.TimerListener;
      import commonj.timers.TimerManager;
      
      /**
       * CommonTimer implementation based on CommonJ TimerManager.
       */
      public class TimerManagerCommonTimerImpl implements CommonTimer {
      
      	/**
      	 * Logger.
      	 */
      	final static LogAdapter LOGGER = LogFactory
      			.getLogger(TimerManagerCommonTimerImpl.class);
      
      	/**
      	 * TimerTasks. Set for tracking purpose.
      	 */
      	private final Set<TimerTask> timerTasks;
      
      	/**
      	 * CommonJ TimerTask wrappers. Set for tracking purpose.
      	 */
      	private final Set<CommonJTimerTaskWrapper> commonJTimerTaskWrappers;
      
      	/**
      	 * TimerManager.
      	 */
      	private final TimerManager timerManager;
      
      	/**
      	 * True if cancelled, false otherwise.
      	 */
      	private boolean cancelled;
      
      	/**
      	 * Constructor.
      	 * 
      	 * @param TimerManager
      	 *            a TimerManager.
      	 */
      	public TimerManagerCommonTimerImpl(TimerManager timerManager) {
      		this.timerManager = timerManager;
      		cancelled = false;
      		timerTasks = Collections.synchronizedSet(new HashSet<TimerTask>());
      		commonJTimerTaskWrappers = Collections
      				.synchronizedSet(new HashSet<CommonJTimerTaskWrapper>());
      	}
      
      	/*
      	 * (without Javadoc)
      	 * 
      	 * @see org.snmp4j.util.CommonTimer#cancel()
      	 */
      	public void cancel() {
      		synchronized (timerTasks) {
      			LOGGER.debug("CommonTimer cancel " + this + " with "
      					+ commonJTimerTaskWrappers.size()
      					+ " CommonJ TimerTask wrapper(s)");
      			// we cancel the CommonTimer
      			cancelled = true;
      			// we cancel each registered task
      			synchronized (commonJTimerTaskWrappers) {
      				for (CommonJTimerTaskWrapper commonJTimerTaskWrapper : commonJTimerTaskWrappers) {
      					try {
      						LOGGER.error("Cancelling CommonJTimerTaskWrapper "
      								+ commonJTimerTaskWrapper);
      						commonJTimerTaskWrapper.timerTask.cancel();
      					} catch (RuntimeException runtimeException) {
      						runtimeException.printStackTrace(System.err);
      						LOGGER.error("Error cancelling TimerTask",
      								runtimeException);
      					}
      					commonJTimerTaskWrapper.timer.cancel();
      				}
      				// we clear resources
      				timerTasks.clear();
      				commonJTimerTaskWrappers.clear();
      			}
      		}
      	}
      
      	/*
      	 * (without Javadoc)
      	 * 
      	 * @see org.snmp4j.util.CommonTimer#schedule(java.util.TimerTask, long)
      	 */
      	public void schedule(TimerTask task, long delay) {
      		if ((delay < 0l) || (delay + System.currentTimeMillis() < 0l)) {
      			throw new IllegalArgumentException("Negative delay.");
      		}
      		synchronized (timerTasks) {
      			registerTimerTask(task);
      			LOGGER.debug("CommonTimer schedule task: " + task.toString()
      					+ " delay: " + delay);
      			final CommonJTimerTaskWrapper commonJTimerTaskWrapper = new CommonJTimerTaskWrapper(
      					task);
      			commonJTimerTaskWrapper.setTimer(timerManager.schedule(
      					commonJTimerTaskWrapper, delay));
      			synchronized (commonJTimerTaskWrappers) {
      				commonJTimerTaskWrappers.add(commonJTimerTaskWrapper);
      			}
      		}
      	}
      
      	/*
      	 * (without Javadoc)
      	 * 
      	 * @see org.snmp4j.util.CommonTimer#schedule(java.util.TimerTask,
      	 *      java.util.Date, long)
      	 */
      	public void schedule(TimerTask task, Date firstTime, long period) {
      		if (firstTime.getTime() < 0l) {
      			throw new IllegalArgumentException("Negative firstTime.");
      		}
      		synchronized (timerTasks) {
      			registerTimerTask(task);
      			LOGGER.debug("CommonTimer schedule task: " + task.toString()
      					+ " firstTime: " + firstTime.toString() + " period: "
      					+ period);
      			final CommonJTimerTaskWrapper commonJTimerTaskWrapper = new CommonJTimerTaskWrapper(
      					task);
      			commonJTimerTaskWrapper.setTimer(timerManager.schedule(
      					commonJTimerTaskWrapper, firstTime, period));
      			synchronized (commonJTimerTaskWrappers) {
      				commonJTimerTaskWrappers.add(commonJTimerTaskWrapper);
      			}
      		}
      	}
      
      	/*
      	 * (without Javadoc)
      	 * 
      	 * @see org.snmp4j.util.CommonTimer#schedule(java.util.TimerTask, long,
      	 *      long)
      	 */
      	public void schedule(TimerTask task, long delay, long period) {
      		if ((delay < 0l) || (delay + System.currentTimeMillis() < 0l)) {
      			throw new IllegalArgumentException("Negative delay.");
      		}
      		synchronized (timerTasks) {
      			registerTimerTask(task);
      			LOGGER.debug("CommonTimer schedule task: " + task.toString()
      					+ " delay: " + delay + " period: " + period);
      			final CommonJTimerTaskWrapper commonJTimerTaskWrapper = new CommonJTimerTaskWrapper(
      					task);
      			commonJTimerTaskWrapper.setTimer(timerManager.schedule(
      					commonJTimerTaskWrapper, delay, period));
      			synchronized (commonJTimerTaskWrappers) {
      				commonJTimerTaskWrappers.add(commonJTimerTaskWrapper);
      			}
      		}
      	}
      
      	/**
      	 * Register a TimerTask.
      	 * 
      	 * @param timerTask
      	 *            a TimerTask.
      	 * @throws IllegalStateException
      	 *             if CommonTimer is cancelled, or TimerTask is scheduled or
      	 *             executed.
      	 */
      	private void registerTimerTask(TimerTask timerTask)
      			throws IllegalStateException {
      		if (cancelled) {
      			final String message = "CommonTimer is cancelled, task "
      					+ timerTask.toString() + " is not scheduled.";
      			LOGGER.debug(message);
      			throw new IllegalStateException(message);
      		}
      		if (!timerTasks.add(timerTask)) {
      			final String message = "Task " + timerTask.toString()
      					+ " is already scheduled or executed.";
      			LOGGER.debug(message);
      			throw new IllegalStateException(message);
      		}
      	}
      
      	/**
      	 * TimerTask wrapper based on CommonJ.
      	 */
      	private class CommonJTimerTaskWrapper implements TimerListener {
      
      		/**
      		 * TimerTask.
      		 */
      		private TimerTask timerTask;
      
      		/**
      		 * Timer.
      		 */
      		private Timer timer;
      
      		/**
      		 * Constructor.
      		 * 
      		 * @param timerTask
      		 *            a TimerTask.
      		 */
      		public CommonJTimerTaskWrapper(TimerTask timerTask) {
      			if (timerTask == null) {
      				throw new NullPointerException("timerTask is required");
      			}
      			this.timerTask = timerTask;
      		}
      
      		/**
      		 * Set Timer.
      		 * 
      		 * @param timer
      		 *            a Timer.
      		 */
      		public void setTimer(Timer timer) {
      			this.timer = timer;
      		}
      
      		/*
      		 * (without Javadoc)
      		 * 
      		 * @see commonj.timers.TimerListener#timerExpired(commonj.timers.Timer)
      		 */
      		public void timerExpired(Timer timer) {
      			LOGGER.debug("Run wrapped TimerTask: " + timerTask.toString());
      			try {
      				timerTask.run();
      			} finally {
      				// should we remove task?
      				if (timer.getPeriod() == 0l) {
      					// task is not going to repeat
      					LOGGER.debug("Removing wrapped TimerTask: "
      							+ timerTask.toString());
      					// we cancel task
      					try {
      						timerTask.cancel();
      					} finally {
      						timer.cancel();
      						// we remove task
      						synchronized (timerTasks) {
      							timerTasks.remove(this.timerTask);
      							synchronized (commonJTimerTaskWrappers) {
      								commonJTimerTaskWrappers.remove(this);
      							}
      						}
      					}
      				}
      			}
      		}
      	}
      
      }
      Extract from applicacionContext.xml for a J2EE/CommonJ environment:

      <jee:jndi-lookup id="timerManager" jndi-name=
      "yourTimerManagerReferenceName" />

      <bean id="snmp4jTimerFactory"
      class=
      "org.snmp4j.util.commonj.TimerManagerTimerFactoryI mpl">
      <constructor-arg ref="timerManager" />
      </bean>


      If you find it useful, please post some feedback.
      Thanks.

      Regards
      Last edited by jarodcanal; Mar 22nd, 2010, 05:28 AM.

      Comment

      Working...
      X