Java tutorial
/* * NOTE: This copyright doesnot cover user programs that use HQ program services * by normal system calls through the application program interfaces provided as * part of the Hyperic Plug-in Development Kit or the Hyperic Client Development * Kit - this is merely considered normal use of the program, and doesnot fall * under the heading of "derived work". Copyright (C) [2004-2009], Hyperic, Inc. * This file is part of HQ. HQ is free software; you can redistribute it and/or * modify it under the terms version 2 of the GNU General Public License as * published by the Free Software Foundation. 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, write * to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. */ package org.hyperic.hq.bizapp.server.mdb; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; import javax.annotation.PostConstruct; import javax.jms.JMSException; import javax.jms.Message; import javax.jms.MessageListener; import javax.jms.ObjectMessage; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hyperic.hq.bizapp.server.shared.HeartbeatCurrentTime; import org.hyperic.hq.events.AbstractEvent; import org.hyperic.hq.events.EventTypeException; import org.hyperic.hq.events.HeartBeatEvent; import org.hyperic.hq.events.TriggerInterface; import org.hyperic.hq.events.ext.RegisterableTriggerInterface; import org.hyperic.hq.events.ext.RegisteredTriggers; import org.hyperic.hq.stats.ConcurrentStatsCollector; import org.hyperic.util.TimeUtil; import org.springframework.beans.factory.annotation.Autowired; /** * The RegisteredDispatcher Message-Drive Bean registers Triggers and dispatches * events to them * <p> * * </p> * TODO: Check if dups-ok maps correctly to the expected non-transaction semantics. * * This is intentionally NOT TRANSACTIONAL. Had to mark it specifically as NotSupported b/c MDBs are required to have some type of transactional boundary. * We are specifically NOT interacting with database or Hibernate sessions during message processing for performance reasons * Bound to topic/eventsTopic */ public class RegisteredDispatcherImpl implements MessageListener, HeartbeatCurrentTime { private final Log log = LogFactory.getLog(RegisteredDispatcherImpl.class); private RegisteredTriggers registeredTriggers; private ConcurrentStatsCollector concurrentStatsCollector; private AtomicLong heartbeatTime = new AtomicLong(); @Autowired public RegisteredDispatcherImpl(RegisteredTriggers registeredTriggers, ConcurrentStatsCollector concurrentStatsCollector) { this.registeredTriggers = registeredTriggers; this.concurrentStatsCollector = concurrentStatsCollector; this.heartbeatTime.set(System.currentTimeMillis()); } @PostConstruct public void initStatsCollector() { concurrentStatsCollector.register(ConcurrentStatsCollector.EVENT_PROCESSING_TIME); } /** * Dispatch the event to interested triggers. * * @param event The event. */ private void dispatchEvent(AbstractEvent event) { // Get interested triggers Collection<RegisterableTriggerInterface> triggers = getInterestedTriggers(event); if (log.isDebugEnabled()) { log.debug("There are " + triggers.size() + " registered for event"); } // Dispatch to each trigger for (RegisterableTriggerInterface registerableTrigger : triggers) { TriggerInterface trigger = (TriggerInterface) registerableTrigger; long startTime = System.currentTimeMillis(); try { trigger.processEvent(event); concurrentStatsCollector.addStat(System.currentTimeMillis() - startTime, ConcurrentStatsCollector.EVENT_PROCESSING_TIME); } catch (EventTypeException e) { // The trigger was not meant to process this event log.error("dispatchEvent dispatched to trigger (" + trigger.getClass() + " that's not " + "configured to handle this type of event: " + event.getClass(), e); } catch (Exception e) { // handle everything here log.error("Failed to dispatch event", e); } } } protected Collection<RegisterableTriggerInterface> getInterestedTriggers(AbstractEvent evt) { return registeredTriggers.getInterestedTriggers(evt); } /** * The onMessage method * */ @SuppressWarnings("unchecked") public void onMessage(Message inMessage) { if (!(inMessage instanceof ObjectMessage)) { return; } final boolean debug = log.isDebugEnabled(); Object obj; try { ObjectMessage om = (ObjectMessage) inMessage; if (debug) { log.debug("Redelivering message=" + inMessage.getJMSRedelivered()); } obj = om.getObject(); } catch (JMSException e) { log.error("Cannot open message object", e); return; } if (obj instanceof HeartBeatEvent) { final HeartBeatEvent event = (HeartBeatEvent) obj; final long timestamp = event.getTimestamp(); if (debug) log.debug("setting heartbeat timestamp to " + TimeUtil.toString(timestamp)); heartbeatTime.set(timestamp); } if (obj instanceof AbstractEvent) { AbstractEvent event = (AbstractEvent) obj; if (debug) { log.debug("1 event in the message"); } dispatchEvent(event); } else if (obj instanceof Collection<?>) { Collection<AbstractEvent> events = (Collection<AbstractEvent>) obj; if (debug) { log.debug(events.size() + " events in the message"); } for (AbstractEvent event : events) { dispatchEvent(event); } } } public long getTimeMillis() { return heartbeatTime.get(); } }