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



_______________________________________________
Jboss-development mailing list
[EMAIL PROTECTED]
http://lists.sourceforge.net/lists/listinfo/jboss-development

Reply via email to