/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2009-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.sms.ping.internal;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
import org.apache.log4j.Logger;
import org.opennms.protocols.rt.Request;
import org.opennms.sms.ping.PingRequestId;
import org.opennms.sms.ping.PingResponseCallback;
import org.smslib.InboundMessage;
import org.smslib.OutboundMessage;
/**
* This class is used to encapsulate a ping request. A request consist of
* the pingable address and a signaled state.
*
* @author <a href="mailto:ranger@opennms.org">Ben Reed</a>
* @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
* @author <a href="mailto:ranger@opennms.org">Ben Reed</a>
* @author <a href="mailto:brozow@opennms.org">Mathew Brozowski</a>
* @version $Id: $
*/
final public class PingRequest implements Request<PingRequestId, PingRequest, PingReply> {
/**
* The id representing the packet
*/
private PingRequestId m_id;
/**
* the request packet
*/
private OutboundMessage m_request = null;
/**
* the response packet
*/
private InboundMessage m_response = null;
/**
* The callback to use when this object is ready to do something
*/
private PingResponseCallback m_callback = null;
/**
* How many retries
*/
private int m_retries;
/**
* how long to wait for a response
*/
private long m_timeout;
/**
* The expiration time of this request
*/
private long m_expiration = -1L;
/**
* The thread logger associated with this request.
*/
private Logger m_log;
private Long m_sentTimestamp;
private Long m_responseTimestamp;
private volatile boolean m_processed = false;
PingRequest(PingRequestId id, long timeout, int retries, Logger logger, PingResponseCallback cb) {
m_id = id;
m_retries = retries;
m_timeout = timeout;
m_log = logger;
m_callback = cb;
m_expiration = System.currentTimeMillis() + timeout;
m_request = new OutboundMessage(id.getDestination(), "ping");
m_request.setSrcPort(6996);
m_request.setValidityPeriod(1);
}
/**
* <p>Constructor for PingRequest.</p>
*
* @param id a {@link org.opennms.sms.ping.PingRequestId} object.
* @param timeout a long.
* @param retries a int.
* @param cb a {@link org.opennms.sms.ping.PingResponseCallback} object.
*/
public PingRequest(PingRequestId id, long timeout, int retries, PingResponseCallback cb) {
this(id, timeout, retries, Logger.getLogger(PingRequest.class), cb);
}
/**
* <p>getId</p>
*
* @return a {@link org.opennms.sms.ping.PingRequestId} object.
*/
public PingRequestId getId() {
return m_id;
}
/**
* <p>getRetries</p>
*
* @return a int.
*/
public int getRetries() {
return m_retries;
}
/**
* <p>getTimeout</p>
*
* @return a long.
*/
public long getTimeout() {
return m_timeout;
}
/**
* <p>getRequest</p>
*
* @return a {@link org.smslib.OutboundMessage} object.
*/
public OutboundMessage getRequest() {
return m_request;
}
/**
* <p>getResponse</p>
*
* @return a {@link org.smslib.InboundMessage} object.
*/
public InboundMessage getResponse() {
return m_response;
}
/**
* <p>getExpiration</p>
*
* @return a long.
*/
public long getExpiration() {
return m_expiration;
}
private Logger log() {
return m_log;
}
/**
* <p>processResponse</p>
*
* @param reply a {@link org.opennms.sms.ping.internal.PingReply} object.
* @return a boolean.
*/
public boolean processResponse(PingReply reply) {
try {
setResponseTimestamp(reply.getReceiveTimestamp());
processResponse(reply.getPacket());
return true;
} finally {
m_processed = true;
}
}
private void processResponse(InboundMessage packet) {
m_response = packet;
log().debug(System.currentTimeMillis()+": Ping Response Received "+this);
m_callback.handleResponse(this, packet);
}
/**
* <p>processTimeout</p>
*
* @return a {@link org.opennms.sms.ping.internal.PingRequest} object.
*/
public PingRequest processTimeout() {
try {
PingRequest returnval = null;
if (this.isExpired()) {
if (this.getRetries() > 0) {
returnval = new PingRequest(getId(), getTimeout(), getRetries() - 1, log(), m_callback);
log().debug(System.currentTimeMillis()+": Retrying Ping Request "+returnval);
} else {
log().debug(System.currentTimeMillis()+": Ping Request Timed out "+this);
m_callback.handleTimeout(this, getRequest());
}
}
return returnval;
} finally {
m_processed = true;
}
}
/**
* <p>isExpired</p>
*
* @return a boolean.
*/
public boolean isExpired() {
return (System.currentTimeMillis() >= getExpiration());
}
/**
* <p>toString</p>
*
* @return a {@link java.lang.String} object.
*/
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('[');
sb.append("ID=").append(getId()).append(',');
sb.append("Retries=").append(getRetries()).append(",");
sb.append("Timeout=").append(getTimeout()).append(",");
sb.append("Expiration=").append(getExpiration()).append(',');
sb.append("Callback=").append(m_callback).append(',');
sb.append("Request=").append(m_request);
sb.append("]");
return sb.toString();
}
/** {@inheritDoc} */
public long getDelay(TimeUnit unit) {
return unit.convert(getExpiration() - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
}
/**
* <p>compareTo</p>
*
* @param request a {@link java.util.concurrent.Delayed} object.
* @return a int.
*/
public int compareTo(Delayed request) {
long myDelay = getDelay(TimeUnit.MILLISECONDS);
long otherDelay = request.getDelay(TimeUnit.MILLISECONDS);
if (myDelay < otherDelay) return -1;
if (myDelay == otherDelay) return 0;
return 1;
}
/** {@inheritDoc} */
public void processError(Throwable t) {
try {
m_callback.handleError(this, getRequest(), t);
} finally {
m_processed = true;
}
}
/**
* <p>setSentTimestamp</p>
*
* @param millis a {@link java.lang.Long} object.
*/
public void setSentTimestamp(Long millis){
m_sentTimestamp = millis;
}
/**
* <p>setResponseTimestamp</p>
*
* @param millis a {@link java.lang.Long} object.
*/
public void setResponseTimestamp(Long millis){
m_responseTimestamp = millis;
}
/**
* <p>getRoundTripTime</p>
*
* @return a long.
*/
public long getRoundTripTime(){
return m_responseTimestamp - m_sentTimestamp;
}
/**
* <p>isProcessed</p>
*
* @return a boolean.
*/
public boolean isProcessed() {
return m_processed;
}
}