/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2008-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 The OpenNMS Group, Inc.
*
* OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
*
* OpenNMS(R) is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation, either version 3 of the License,
* or (at your option) any later version.
*
* OpenNMS(R) 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 OpenNMS(R). If not, see:
* http://www.gnu.org/licenses/
*
* For more information contact:
* OpenNMS(R) Licensing <license@opennms.org>
* http://www.opennms.org/
* http://www.opennms.com/
*******************************************************************************/
package org.opennms.netmgt.dao;
import java.util.LinkedList;
import java.util.List;
import org.opennms.netmgt.model.events.EventForwarder;
import org.opennms.netmgt.xml.event.Event;
import org.opennms.netmgt.xml.event.Events;
import org.opennms.netmgt.xml.event.Log;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.support.ResourceHolderSupport;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;
/**
* <p>TransactionAwareEventForwarder class.</p>
*
* @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
* @author <a href="mailto:dj@opennms.org">DJ Gregor</a>
*/
public class TransactionAwareEventForwarder implements EventForwarder,
InitializingBean {
/**
* <p>Constructor for TransactionAwareEventForwarder.</p>
*/
public TransactionAwareEventForwarder() {
}
/**
* <p>Constructor for TransactionAwareEventForwarder.</p>
*
* @param forwarder a {@link org.opennms.netmgt.model.events.EventForwarder} object.
* @throws java.lang.Exception if any.
*/
public TransactionAwareEventForwarder(EventForwarder forwarder)
throws Exception {
setEventForwarder(forwarder);
afterPropertiesSet();
}
public static class PendingEventsSynchronization extends
TransactionSynchronizationAdapter {
private PendingEventsHolder m_eventsHolder;
private EventForwarder m_eventForwarder;
public PendingEventsSynchronization(PendingEventsHolder eventsHolder,
EventForwarder eventForwarder) {
m_eventsHolder = eventsHolder;
m_eventForwarder = eventForwarder;
}
@Override
public void afterCommit() {
if (!m_eventsHolder.hasPendingEvents()) {
return;
}
List<Log> pendingEvents = m_eventsHolder.consumePendingEvents();
for (Log events : pendingEvents) {
m_eventForwarder.sendNow(events);
}
}
@Override
public void afterCompletion(int status) {
if (TransactionSynchronizationManager.hasResource(m_eventForwarder)) {
TransactionSynchronizationManager
.unbindResource(m_eventForwarder);
}
}
}
public static class PendingEventsHolder extends ResourceHolderSupport {
private List<Log> m_pendingEvents = null;
public PendingEventsHolder(List<Log> pendingEvents) {
m_pendingEvents = pendingEvents;
}
public synchronized List<Log> consumePendingEvents() {
List<Log> pendingEvents = m_pendingEvents;
m_pendingEvents = null;
return pendingEvents;
}
public List<Log> getPendingEvents() {
return m_pendingEvents;
}
@Override
public void clear() {
m_pendingEvents = null;
}
public boolean hasPendingEvents() {
return m_pendingEvents != null;
}
public void setPendingEventsList(List<Log> pendingEvents) {
m_pendingEvents = pendingEvents;
}
}
private EventForwarder m_eventForwarder;
/**
* <p>setEventForwarder</p>
*
* @param eventForwarder a {@link org.opennms.netmgt.model.events.EventForwarder} object.
*/
public void setEventForwarder(EventForwarder eventForwarder) {
m_eventForwarder = eventForwarder;
}
/**
* <p>afterPropertiesSet</p>
*
* @throws java.lang.Exception if any.
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(m_eventForwarder != null,
"eventForwarder property must be set");
}
/** {@inheritDoc} */
public void sendNow(Event event) {
Log eventLog = new Log();
Events events = new Events();
eventLog.setEvents(events);
events.addEvent(event);
sendNow(eventLog);
}
/**
* <p>sendNow</p>
*
* @param eventLog a {@link org.opennms.netmgt.xml.event.Log} object.
*/
public void sendNow(Log eventLog) {
List<Log> pendingEvents = requestPendingEventsList();
pendingEvents.add(eventLog);
releasePendingEventsList(pendingEvents);
}
/**
* <p>requestPendingEventsList</p>
*
* @return a {@link java.util.List} object.
*/
public List<Log> requestPendingEventsList() {
PendingEventsHolder eventsHolder = (PendingEventsHolder) TransactionSynchronizationManager
.getResource(m_eventForwarder);
if (eventsHolder != null
&& (eventsHolder.hasPendingEvents() || eventsHolder
.isSynchronizedWithTransaction())) {
eventsHolder.requested();
if (!eventsHolder.hasPendingEvents()) {
eventsHolder.setPendingEventsList(new LinkedList<Log>());
}
return eventsHolder.getPendingEvents();
}
List<Log> pendingEvents = new LinkedList<Log>();
if (TransactionSynchronizationManager.isSynchronizationActive()) {
PendingEventsHolder holderToUse = eventsHolder;
if (holderToUse == null) {
holderToUse = new PendingEventsHolder(pendingEvents);
} else {
holderToUse.setPendingEventsList(pendingEvents);
}
holderToUse.requested();
TransactionSynchronizationManager
.registerSynchronization(new PendingEventsSynchronization(
holderToUse, m_eventForwarder));
holderToUse.setSynchronizedWithTransaction(true);
if (holderToUse != eventsHolder) {
TransactionSynchronizationManager.bindResource(
m_eventForwarder, holderToUse);
}
}
return pendingEvents;
}
/**
* <p>releasePendingEventsList</p>
*
* @param pendingEvents a {@link java.util.List} object.
*/
public void releasePendingEventsList(List<Log> pendingEvents) {
if (pendingEvents == null) {
return;
}
PendingEventsHolder eventsHolder = (PendingEventsHolder) TransactionSynchronizationManager
.getResource(m_eventForwarder);
if (eventsHolder != null
&& eventHolderHolds(eventsHolder, pendingEvents)) {
// It's the transactional Connection: Don't close it.
eventsHolder.released();
} else {
for (Log log : pendingEvents) {
m_eventForwarder.sendNow(log);
}
}
}
private boolean eventHolderHolds(PendingEventsHolder eventsHolder,
List<Log> passedInEvents) {
if (!eventsHolder.hasPendingEvents()) {
return false;
}
return (eventsHolder.getPendingEvents() == passedInEvents);
}
}