From: Burkhard V. <Bur...@we...> - 2001-06-19 16:14:32
|
Hi, hmm, this is going to get a bit lengthy. What I did so far. I implemented my own timer service extending the javax.management.timer class, to intercept timer addNotification calls and store these in a database before handing them to the Timer (super-)class. If JBoss somehow fails I restore all upcoming Notifications and add a Listener class. For convinience reasons I want to use a Listener which does an lookup to a previously deployed enterprise bean and hands the Notification to this bean. So far so good. I got the TimerDB class starting fine, addNotifications stores Notifications in the DB, on restart all Notifications are restored BUT the Listener class gives me a Headache. The Bean to look after is provided by an MBean attribute tag, and (after throwing a jar with only Home and Remote interfaces into lib/ext) lookups fine. To be fully independent regarding this given paramenter I cast the looked up class to javax.ejb.EJBHome which works fine, but EJBHome has no create method to get the Remote interface. So I try to use the Reflection API and yes I can get the create method of the Bean, BUT in order to invoke this method I need to call Method.invoke(Object, Object[] args). I'm quite sure this is going to work if anyone can tell me how to invoke giving nothing as parameter (as create usually does). invoke(null, null) gives a NPE, invoke(java.lang.Void.TYPE, new Object[]{java.lang.Void.TYPE}) gives IllegalArgumentException: object is not an instance of declaring class. BTW: The Bean I lookup implements a special interface which extends SessionBean and NotificationHandle. To help making things clearer here are the mbean entry in jboss.jcml, the relevant parts of the TimerDB class and all interfaces I use. <mbean code="org.jboss.timer.TimerDB" name=":service=Timer"> <attribute name="DataSource">OracleRemoteDB</attribute> <attribute name="ListenerBean">ejb/TimerListener</attribute> </mbean> (Yes, I repackage jboss.jar...) ****************************************************************** Timer DB Class ****************************************************************** public class TimerDB extends Timer implements TimerDBMBean, org.jboss.util.Service { public class Listener implements NotificationListener { private TimerDBListener timerListener; public Listener(String ListenerBean) throws Exception { try { javax.ejb.EJBHome m_TLH = (javax.ejb.EJBHome) new InitialContext().lookup(ListenerBean); log.log("Listener create: Lookup succesful"); log.log("Listener create: HomeInterface: " + m_TLH.getEJBMetaData().getHomeInterfaceClass()); java.lang.reflect.Method obj = m_TLH.getClass().getMethod("create", null); Object test = obj.invoke(java.lang.Void.TYPE, new Object[]{java.lang.Void.TYPE}); log.log("Listener create: Create succesful: " + test.getClass()); timerListener = (TimerDBListener)test; log.log("Listener create: Cast succesful"); } catch(NamingException Ex) { log.error("The ListenerBean \"" + ListenerBean +"\" could not be found."); log.exception(Ex); throw Ex; } } public void handleNotification(Notification pNotification, Object pHandback) { try { log.debug("Timer hit:"); timerListener.handleNotification(pNotification, pHandback); } catch (Exception Ex) { log.exception(Ex); } } } [ leaving out loads of DB and Service relevant stuff] protected void startService() throws Exception { super.start(); // Now setting all future notifications from the DB. Connection con=null; PreparedStatement prepStmt=null; ResultSet rs=null; try { InitialContext context = new InitialContext(); log.debug("Using Database " + dataSourceName); dataSource = (DataSource)new InitialContext().lookup(dataSourceName); con = dataSource.getConnection(); prepStmt = con.prepareStatement("SELECT TIMERTYPE, TIMERMESSAGE, TIMERDATA, TIMERDATE, " + "TIMERDELAY, TIMERREPEAT FROM TIMERDB WHERE TIMERDATE >= ?" ); prepStmt.setTimestamp(1, new java.sql.Timestamp(new Date().getTime())); rs = prepStmt.executeQuery(); while( rs.next() ) { Object obj = Deserialize(rs.getBytes("TIMERDATA")); log.error("Restoring: " + rs.getString("TIMERTYPE") + ", " + rs.getString("TIMERMESSAGE") + ", " + obj + ", " + rs.getTimestamp("TIMERDATE") + ", " + rs.getLong("TIMERDELAY") + ", " + rs.getLong("TIMERREPEAT")); super.addNotification(rs.getString("TIMERTYPE"), rs.getString("TIMERMESSAGE"), obj, rs.getTimestamp("TIMERDATE"), rs.getLong("TIMERDELAY"), rs.getLong("TIMERREPEAT")); } try { listener = new Listener(listenerBeanName); } catch(NamingException Ex) {} mbServer.addNotificationListener(new ObjectName("DefaultDomain", "service", "Timer"), listener, null, null ); } catch(NamingException Ex) { log.error("The DataSource \"" + dataSourceName +"\" could not be found.");// throw Ex; } catch(SQLException Ex) { log.error("Error accessing DataSource"); throw Ex; } finally { if( rs!=null) try { rs.close(); } catch(Exception Ex) { rs=null; } if( prepStmt!=null) try { prepStmt.close(); } catch(Exception Ex) { prepStmt=null; } if( con!=null) try { con.close(); } catch(Exception Ex) { con=null; } } } [some more stuff....] *********************************************************************** TimerDBListener interface *********************************************************************** package org.jboss.timer; import javax.management.NotificationListener; import javax.ejb.SessionBean; public interface TimerDBListener extends SessionBean, NotificationListener { } *********************************************************************** TimerDBMBean interface *********************************************************************** package org.jboss.timer; public interface TimerDBMBean extends javax.management.timer.TimerMBean, org.jboss.util.ServiceMBean { // Constants ----------------------------------------------------- public static final String OBJECT_NAME = ":service=timer"; // Public -------------------------------------------------------- public void setDataSource(String _dataSourceName); public void setListenerBean(String _listenerBeanName); } If someone needs the full source and more details I will supply anything I have, and tried. If anyone comes up with a better idea, go ahead, I allready tried to declare my own TimerDBEJBHome interface which as a create method, which I then could use, I evan got a EJB deployed (although with loads of warnings), but I gave the TimerDBListener interface as return type and this didn't work with real beans (ClassCastException). Please Help, Burkhard |