package org.jdiameter.client.impl.parser;
/*
* Copyright (c) 2006 jDiameter.
* https://jdiameter.dev.java.net/
*
* License: GPL v3
*
* e-mail: erick.svenson@yahoo.com
*
*/
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.jdiameter.api.Answer;
import org.jdiameter.api.ApplicationId;
import org.jdiameter.api.Avp;
import org.jdiameter.api.AvpDataException;
import org.jdiameter.api.AvpSet;
import org.jdiameter.api.InternalException;
import org.jdiameter.api.MetaData;
import org.jdiameter.client.api.IEventListener;
import org.jdiameter.client.api.IMessage;
import org.jdiameter.client.api.controller.IPeer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MessageImpl implements IMessage {
private static final long serialVersionUID = 1L;
protected static Logger logger = LoggerFactory.getLogger(MessageImpl.class);
int state = STATE_NOT_SENT;
short version = 1, flags;
int commandCode;
long applicationId;
long hopByHopId;
boolean notMutableHopByHop;
long endToEndId;
AvpSetImpl avpSet;
boolean isNetworkRequest = false;
transient IPeer peer;
transient MessageParser parser;
transient TimerTask timerTask;
transient IEventListener listener;
/**
* Create empry message
* @param parser
* @param commandCode
* @param appId
*/
MessageImpl(MessageParser parser, int commandCode, long appId) {
this.commandCode = commandCode;
this.applicationId = appId;
this.parser = parser;
this.avpSet = new AvpSetImpl(parser);
this.endToEndId = parser.getNextEndToEndId();
}
/**
* Create empty message
* @param parser
* @param commandCode
* @param applicationId
* @param flags
* @param hopByHopId
* @param endToEndId
* @param avpSet
*/
MessageImpl(MessageParser parser, int commandCode, long applicationId, short flags, long hopByHopId, long endToEndId, AvpSetImpl avpSet) {
this(parser, commandCode, applicationId);
this.flags = flags;
this.hopByHopId = hopByHopId;
this.endToEndId = endToEndId;
if (avpSet != null) {
this.avpSet = avpSet;
}
}
/**
* Create empry message
* @param metaData
* @param parser
* @param commandCode
* @param appId
*/
MessageImpl(MetaData metaData, MessageParser parser, int commandCode, long appId) {
this(parser, commandCode, appId);
try {
getAvps().addAvp(Avp.ORIGIN_HOST, metaData.getLocalPeer().getUri().getFQDN(), true, false, true);
getAvps().addAvp(Avp.ORIGIN_REALM, metaData.getLocalPeer().getRealmName(), true, false, true);
}
catch (Exception e) {
logger.debug("Can not create message", e);
}
}
/**
* Create Answer
* @param request parent request
*/
private MessageImpl(MessageImpl request) {
this(request.parser, request.getCommandCode(), request.getHeaderApplicationId());
copyHeader(request);
//
setRequest(false);
parser.copyBasicAvps(this, request, true);
}
public byte getVersion() {
return (byte) version;
}
public boolean isRequest() {
return (flags & 0x80) != 0;
}
public void setRequest(boolean b) {
if (b) {
flags |= 0x80;
}
else {
flags &= 0x7F;
}
}
public boolean isProxiable() {
return (flags & 0x40) != 0;
}
public void setProxiable(boolean b) {
if (b) {
flags |= 0x40;
}
else {
flags &= 0xBF;
}
}
public boolean isError() {
return (flags & 0x20) != 0;
}
public void setError(boolean b) {
if (b) {
flags |= 0x20;
}
else {
flags &= 0xDF;
}
}
public boolean isReTransmitted() {
return (flags & 0x10) != 0;
}
public void setReTransmitted(boolean b) {
if (b) {
flags |= 0x10;
}
else {
flags &= 0xEF;
}
}
public int getCommandCode() {
return this.commandCode;
}
public String getSessionId() {
try {
Avp avpSessionId = avpSet.getAvp(Avp.SESSION_ID);
return avpSessionId != null ? avpSessionId.getUTF8String() : null;
}
catch(AvpDataException exc) {
return null;
}
}
public Answer createAnswer(long resultCode) {
MessageImpl answer = new MessageImpl(this);
try {
answer.getAvps().addAvp(Avp.RESULT_CODE, resultCode, true, false, true);
}
catch (Exception e) {
logger.debug("Can not create answer message", e);
}
answer.setRequest(false);
return answer;
}
public Answer createAnswer(long vendorId, long experementalResultCode) {
MessageImpl answer = new MessageImpl(this);
try {
AvpSet exp_code = answer.getAvps().addGroupedAvp(297, true, false);
exp_code.addAvp(Avp.VENDOR_ID, vendorId, true, false, true);
exp_code.addAvp(Avp.EXPERIMENTAL_RESULT_CODE, experementalResultCode, true, false, true);
}
catch (Exception e) {
logger.debug("Can not create answer message", e);
}
answer.setRequest(false);
return answer;
}
public long getApplicationId() {
return applicationId;
}
public ApplicationId getSingleApplicationId() {
return getSingleApplicationId(this.applicationId);
}
public ApplicationId getSingleApplicationId(long applicationId) {
Set<ApplicationId> appIds = getApplicationIdAvps();
ApplicationId first = null;
for (ApplicationId id: appIds) {
if (first == null) {
first = id;
}
if (applicationId != 0 && id.getVendorId() == 0 && applicationId == id.getAuthAppId()) {
return id;
}
if (applicationId != 0 && id.getVendorId() == 0 && applicationId == id.getAcctAppId()) {
return id;
}
if (applicationId != 0 && ( applicationId == id.getAuthAppId() || applicationId == id.getAcctAppId())) {
return id;
}
}
return first;
}
public Set<ApplicationId> getApplicationIdAvps() {
Set<ApplicationId> rc = new LinkedHashSet<ApplicationId>();
try {
AvpSet authAppId = avpSet.getAvps(Avp.AUTH_APPLICATION_ID);
for (Avp anAuthAppId : authAppId) {
rc.add(ApplicationId.createByAuthAppId(( anAuthAppId).getInteger32()));
}
AvpSet accAppId = avpSet.getAvps(Avp.ACCT_APPLICATION_ID);
for (Avp anAccAppId : accAppId) {
rc.add(ApplicationId.createByAccAppId(( anAccAppId).getInteger32()));
}
AvpSet specAppId = avpSet.getAvps(Avp.VENDOR_SPECIFIC_APPLICATION_ID);
for (Avp aSpecAppId : specAppId) {
long vendorId = 0, acctApplicationId = 0, authApplicationId = 0;
AvpSet avps = ( aSpecAppId).getGrouped();
for (Avp localAvp : avps) {
if (localAvp.getCode() == Avp.VENDOR_ID) {
vendorId = localAvp.getUnsigned32();
}
if (localAvp.getCode() == Avp.AUTH_APPLICATION_ID) {
authApplicationId = localAvp.getUnsigned32();
}
if (localAvp.getCode() == Avp.ACCT_APPLICATION_ID) {
acctApplicationId = localAvp.getUnsigned32();
}
}
if ( authApplicationId != 0 ) {
rc.add(ApplicationId.createByAuthAppId(vendorId, authApplicationId));
}
if ( acctApplicationId != 0 ) {
rc.add(ApplicationId.createByAccAppId(vendorId, acctApplicationId));
}
}
}
catch (Exception exception) {
return new LinkedHashSet<ApplicationId>();
}
return rc;
}
public long getHopByHopIdentifier() {
return hopByHopId;
}
public long getEndToEndIdentifier() {
return endToEndId;
}
public AvpSet getAvps() {
return avpSet;
}
protected void copyHeader(MessageImpl request) {
endToEndId = request.endToEndId;
hopByHopId = request.hopByHopId;
version = request.version;
flags = request.flags;
peer = request.peer;
}
public Avp getResultCode() {
return getAvps().getAvp(Avp.RESULT_CODE);
}
public void setNetworkRequest(boolean isNetworkRequest) {
this.isNetworkRequest = isNetworkRequest;
}
public boolean isNetworkRequest() {
return isNetworkRequest;
}
public boolean isWrapperFor(Class<?> aClass) throws InternalException {
return false;
}
public <T> T unwrap(Class<T> aClass) throws InternalException {
return null;
}
// Inner API
public void setHopByHopIdentifier(long hopByHopId) {
if (hopByHopId < 0 ) {
this.hopByHopId = -hopByHopId;
this.notMutableHopByHop = true;
}
else {
if (!this.notMutableHopByHop) {
this.hopByHopId = hopByHopId;
}
}
}
public void setEndToEndIdentifier(long endByEndId) {
this.endToEndId = endByEndId;
}
public IPeer getPeer() {
return peer;
}
public void setPeer(IPeer peer) {
this.peer = peer;
}
public int getState() {
return state;
}
public long getHeaderApplicationId() {
return applicationId;
}
public void setHeaderApplicationId(long applicationId) {
this.applicationId = applicationId;
}
public int getFlags() {
return flags;
}
public void setState(int newState) {
state = newState;
}
public void createTimer(ScheduledExecutorService scheduledFacility, long timeOut, TimeUnit timeUnit) {
timerTask = new TimerTask(this);
timerTask.setTimerHandler(scheduledFacility.schedule(timerTask, timeOut, timeUnit));
}
public void runTimer() {
if (timerTask != null && !timerTask.isDone() && !timerTask.isCancelled()) {
timerTask.run();
}
}
public boolean isTimeOut() {
return timerTask != null && timerTask.isDone() && !timerTask.isCancelled();
}
public void setListener(IEventListener listener) {
this.listener = listener;
}
public IEventListener getEventListener() {
return listener;
}
public void clearTimer() {
if (timerTask != null) {
timerTask.cancel();
}
}
public String toString() {
return "MessageImpl{" + "commandCode=" + commandCode + ", flags=" + flags + '}';
}
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
MessageImpl message = (MessageImpl) o;
return applicationId == message.applicationId && commandCode == message.commandCode &&
endToEndId == message.endToEndId && hopByHopId == message.hopByHopId;
}
public int hashCode() {
long result;
result = commandCode;
result = 31 * result + applicationId;
result = 31 * result + hopByHopId;
result = 31 * result + endToEndId;
return new Long(result).hashCode();
}
public String getDuplicationKey() {
try {
return getDuplicationKey(
getAvps().getAvp(Avp.ORIGIN_HOST).getOctetString(), getEndToEndIdentifier()
);
}
catch (AvpDataException e) {
throw new IllegalArgumentException(e);
}
}
public String getDuplicationKey(String host, long endToEndId) {
return host + endToEndId;
}
public Object clone() {
try {
return parser.createMessage(parser.encodeMessage(this));
}
catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
protected static class TimerTask implements Runnable{
ScheduledFuture timerHandler;
MessageImpl message;
public TimerTask(MessageImpl message) {
this.message = message;
}
public void setTimerHandler(ScheduledFuture timerHandler) {
this.timerHandler = timerHandler;
}
public void run() {
try {
if (message != null && message.state != STATE_ANSWERED) {
IEventListener listener = null;
if ( message.listener instanceof IEventListener) {
listener = message.listener;
}
if (listener != null && listener.isValid()) {
if (message.peer != null) {
message.peer.remMessage(message);
}
message.listener.timeoutExpired(message);
}
}
}
catch(Throwable e) {
logger.debug("Can not process timeout", e);
}
}
public void cancel() {
if (timerHandler != null) {
timerHandler.cancel(true);
}
message = null;
}
public boolean isDone() {
return timerHandler != null && timerHandler.isDone();
}
public boolean isCancelled() {
return timerHandler == null || timerHandler.isCancelled();
}
}
}