/* Release Version : 3.0 Alpha
*
* Date: dd/mm/06
*
* Copyright 2006 University of Southampton School of Electronics and Computer Science
*
* Licensed 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.openoss.opennms.spring.qosd.ejb;
import java.rmi.RemoteException;
import javax.ejb.RemoveException;
import javax.ejb.CreateException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.oss.fm.monitor.AlarmKey;
import javax.oss.fm.monitor.AlarmValue;
import javax.oss.fm.monitor.JVTAlarmMonitorHome;
import javax.oss.fm.monitor.JVTAlarmMonitorSession;
import javax.rmi.PortableRemoteObject;
import org.opennms.core.utils.ThreadCategory;
import org.openoss.opennms.spring.qosd.AlarmListConnectionManager;
import org.openoss.opennms.spring.qosd.PropertiesLoader;
import org.openoss.opennms.spring.qosd.QoSDimpl2;
import org.openoss.ossj.fm.monitor.j2ee.AlarmMonitor;
import java.util.Properties;
import java.util.Hashtable;
import org.openoss.ossj.jvt.fm.monitor.OOSSAlarmValue;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* The AlarmListJ2eeConnectionManagerThread tries to register with the AlarmMonitorBean and maintains the connection
* for the QosD. If the connection is lost, it reestablishes the connection.
*
* @author ranger
* @version $Id: $
*/
public class AlarmListJ2eeConnectionManagerThread extends Thread implements AlarmListConnectionManager
{
private int status = DISCONNECTED;
private PropertiesLoader props;
public Properties env;
private JVTAlarmMonitorHome home;
private JVTAlarmMonitorSession session;
private Object ref;
private AlarmMonitor alarmInternals;
private Hashtable<AlarmKey,AlarmValue> alarmList; // current alarm list - omit cleared and acknowledged alarms
private int send_status = SENT;
private boolean init = false;
private String rebuilt_message="not set";
ThreadCategory log;
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#reset_list(java.lang.String)
*/
/** {@inheritDoc} */
public void reset_list(String _rebuilt_message)
{
this.rebuilt_message = _rebuilt_message;
send_status = REBUILD;
interrupt();
}
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#send(java.util.Hashtable)
*/
/** {@inheritDoc} */
public void send(Hashtable<AlarmKey, AlarmValue> alarmList)
{
this.alarmList = alarmList;
send_status = SEND;
interrupt();
}
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#run()
*/
/**
* <p>run</p>
*
* @throws java.lang.IllegalStateException if any.
*/
public void run() throws IllegalStateException
{
//log.info("Thread started");
/* if the init variable is false then the thread has not been initialised
* yet so throw an IllegalStateException to indicate this.
*/
if(!init)
throw new IllegalStateException("AlarmListJ2eeConnectionManagerThread - You must call init() before calling run()");
while(true)
{
//log.debug("Status = " + status);
//log.debug("Send_status = " + send_status);
/* If we are connected to the bean and we need to
* send some alarms then try to send them. If the
* connection has failed, reconnect.
*/
if((status == CONNECTED) && ((send_status == SEND) | (send_status == REBUILD)) )
{
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.run() Sending alarms");
try
{
if(alarmInternals == null)
log.error("AlarmListJ2eeConnectionManagerThread.run() alarmInternals is null");
if (send_status == REBUILD) {
if(alarmInternals == null) {
log.error("AlarmListJ2eeConnectionManagerThread.run() rebuilt_message is null");
}
alarmInternals.rebuildAlarmList(rebuilt_message);
}
else {
if(alarmList == null)
log.error("AlarmListJ2eeConnectionManagerThread.run() alarmList is null");
alarmInternals.updateAlarmList(alarmList);
}
send_status = SENT;
}
catch(RemoteException remote_ex)
{
log.error("Could not contact bean - reconnection attempt started");
status = DISCONNECTED;
send_status = SEND;
}
catch(NullPointerException np_ex)
{
log.error("alarmInternals is null, JBoss server may be down", np_ex);
log.info("Attempting reconnect");
status = DISCONNECTED;
send_status = SEND;
}
}
/* If we are connected to the bean and we don't
* need to send anything, then test that we are
* still connected. If not try to reestablish the
* connection before we need to use it again.
*/
if(status == CONNECTED && send_status == SENT)
{
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.run() - Polling connection");
/* test if the connection has been lost
* by polling the getVersion method of the
* bean periodically. If the call throws a
* remote exception then the bean connection
* has been lost.
*/
try
{
alarmInternals.getVersion();
}
catch(RemoteException remote_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.run() Could not contact bean - reconnection attempt started");
status = DISCONNECTED;
}
}
/*If we have disconnected from the bean, reconnect
*/
if(status == DISCONNECTED)
{
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.run() Attempting Connecting to bean");
try
{
lookupBean();
status = CONNECTED;
log.info("AlarmListJ2eeConnectionManagerThread.run() Connected to bean");
}
catch(NamingException name_ex)
{
status = DISCONNECTED;
log.error("AlarmListJ2eeConnectionManagerThread.run() NamingException caught, Could not connect to bean", name_ex);
}
catch(RemoteException remote_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.run() RemoteException caught, cannot connect to bean", remote_ex);
status = DISCONNECTED;
}
}
/*routine to halt thread excecution*/
if(status == STOP)
{
log.info("AlarmListJ2eeConnectionManagerThread.run() Stopping thread");
cleanUp();
return;
}
/* Wait for 1 minute between connection/polling attempts
* when interrupted excecution can continue for urgent
* requests such as sending the alarm list.
*/
try
{
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.run() AlarmListJ2eeConnectionManagerThread.run() Going to sleep for 1 minute");
sleep(60000); //wait for 1 minute before trying to reconnect;
}
catch(InterruptedException int_ex)
{
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.run() Thread interrupted");
}
if (log.isDebugEnabled()) {
log.debug("AlarmListJ2eeConnectionManagerThread.run() Waking up");
log.debug("AlarmListJ2eeConnectionManagerThread.run() Connection State = " + status);
log.debug("AlarmListJ2eeConnectionManagerThread.run() send_status = " + send_status);
}
}
}
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#init(org.openoss.opennms.spring.qosd.PropertiesLoader, java.util.Properties)
*/
/** {@inheritDoc} */
public void init(PropertiesLoader props, Properties env)
{
this.props = props;
this.env = env;
log = QoSDimpl2.getLog(); //Get a reference to the QoSD logger
init = true; //inform the thread that it has been initialised
//and can execute the run() method.
}
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#kill()
*/
/* Thread.stop() is unsafe so ending run method by changing
* the status variable that tells the run method to return
* and end execution.
*/
/**
* <p>kill</p>
*/
public void kill()
{
status = STOP;
interrupt();
}
/* (non-Javadoc)
* @see org.openoss.opennms.spring.qosd.ejb.ConnectionManager#getStatus()
*/
/**
* <p>Getter for the field <code>status</code>.</p>
*
* @return a int.
*/
public int getStatus()
{
return status;
}
/**
* Method to find and connect to the remote bean.
*/
private void lookupBean() throws NamingException, RemoteException
{
/* Create a new InitialContext with the properties paramters -
* The starting point of naming resolution
*/
log.info("AlarmListJ2eeConnectionManagerThread.lookupBean() Looking up QoS bean");
InitialContext ic = new InitialContext(env);
log.info("AlarmListJ2eeConnectionManagerThread.lookupBean() InitialContext created");
try
{
ref = ic.lookup(props.getProperty("org.openoss.opennms.spring.qosd.jvthome"));
log.info("AlarmListJ2eeConnectionManagerThread.lookupBean() QoS Bean found");
home = (JVTAlarmMonitorHome) PortableRemoteObject.narrow( ref,
JVTAlarmMonitorHome.class );
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.lookupBean() home initialised");
session = home.create();
if (log.isDebugEnabled()) log.debug("AlarmListJ2eeConnectionManagerThread.lookupBean() Session created");
alarmInternals = (AlarmMonitor) PortableRemoteObject.narrow(
session.getHandle().getEJBObject(), AlarmMonitor.class );
if(alarmInternals == null)
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() AlarmMonitor alarmInternals is null line 244");
}
catch(IllegalArgumentException iae_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() jvthome property does not exist", iae_ex);
}
/*catch(RemoteException remote_ex)
{
log.error("Cannot connect to bean", remote_ex);
status = DISCONNECTED;
}*/
catch(CreateException create_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() Cannot create new session", create_ex);
}
catch(NullPointerException np_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() NullPointerException caught", np_ex);
}
finally
{
ic.close();
}
log.info("AlarmListJ2eeConnectionManagerThread.lookupBean() New bean session started");
}
/**
* Private method to finally clean up the connections
*/
private void cleanUp()
{
try
{
session.remove();
}
catch(RemoveException remove_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() Cannot remove session", remove_ex);
}
catch(RemoteException remote_ex)
{
log.error("AlarmListJ2eeConnectionManagerThread.lookupBean() Connection to bean lost", remote_ex);
}
}
/**
* Makes a new empty alarm value object
* NOTE THIS IS A PATCH to proxy for JVTAlarmMonitorSession.makeAlarmValue()
*
* @return a javax$oss$fm$monitor$AlarmValue object.
*/
public javax.oss.fm.monitor.AlarmValue makeAlarmValue(){
return new OOSSAlarmValue();
}
/**
* Makes a new alarm value object pre-populated with internal objects
* which have been made from a local invarient specification.
* NOTE THIS IS A PATCH to proxy for JVTAlarmMonitorSession
*
* @return a javax$oss$fm$monitor$AlarmValue object.
*/
public javax.oss.fm.monitor.AlarmValue makeAlarmValueFromSpec() {
javax.oss.fm.monitor.AlarmValue alarmValueSpecification = (javax.oss.fm.monitor.AlarmValue)m_context.getBean("alarmValueSpecification");
return alarmValueSpecification;
}
// SPRING DAO SETTERS
/**
* used to hold a local reference to the application context from which this bean was started
*/
private ClassPathXmlApplicationContext m_context=null; // used to passapplication context to OssBeans
/**
* {@inheritDoc}
*
* Used by jmx mbean QoSD to pass in Spring Application context
*/
public void setApplicationContext(ClassPathXmlApplicationContext m_context){
this.m_context = m_context;
}
}