package org.jdiameter.common.impl.validation;
import java.util.HashMap;
import java.util.Map;
import org.jdiameter.api.Avp;
import org.jdiameter.api.AvpDataException;
import org.jdiameter.api.AvpSet;
import org.jdiameter.api.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Start time:10:40:36 2009-05-26<br>
* Project: diameter-parent<br>
* This class represents message/command in validation framework. It contains
* basic info about command along with avp list - their multiplicity and
* allowance.
*
* @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
* @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
* @since 1.5.189
*/
public class VMessageRepresentation implements Comparable<VMessageRepresentation>, Cloneable {
private static final transient Logger log = LoggerFactory.getLogger(VMessageRepresentation.class);
private int commandCode = -1;
private long applicationId = 0;
private boolean isRequest = false;
protected Map<VAvpRepresentation, VAvpRepresentation> messageAvps = new HashMap<VAvpRepresentation, VAvpRepresentation>();
private String name = null;
public VMessageRepresentation(int commandCode, long applicationId, boolean isRequest) {
super();
this.commandCode = commandCode;
this.applicationId = applicationId;
this.isRequest = isRequest;
}
public VMessageRepresentation(int commandCode, long applicationId, boolean isRequest, String name) {
super();
this.commandCode = commandCode;
this.applicationId = applicationId;
this.isRequest = isRequest;
this.name = name;
}
public VMessageRepresentation(VMessageRepresentation clone) {
super();
this.applicationId = clone.applicationId;
this.commandCode = clone.commandCode;
this.isRequest = clone.isRequest;
this.name = clone.name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (applicationId ^ (applicationId >>> 32));
result = prime * result + commandCode;
result = prime * result + (isRequest ? 1231 : 1237);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
VMessageRepresentation other = (VMessageRepresentation) obj;
if (applicationId != other.applicationId)
return false;
if (commandCode != other.commandCode)
return false;
if (isRequest != other.isRequest)
return false;
return true;
}
public Map<VAvpRepresentation, VAvpRepresentation> getMessageAvps() {
return messageAvps;
}
public void setMessageAvps(Map<VAvpRepresentation, VAvpRepresentation> messageAvps) {
this.messageAvps = messageAvps;
}
public int getCommandCode() {
return commandCode;
}
public long getApplicationId() {
return applicationId;
}
public boolean isRequest() {
return isRequest;
}
public String getName() {
return name;
}
/**
* Valdiates messages in terms of contained avps. It checks against
* deinftion if available if all requried avps are set, not allowed avps are
* not present, and number of avps is correct.
*
* @param msg
* @throws JAvpNotAllowedException
*/
public void validate(Message msg) throws JAvpNotAllowedException {
for (VAvpRepresentation ap : this.messageAvps.values()) {
AvpSet innerSet = msg.getAvps().getAvps(ap.getCode(), ap.getVendorId());
int count = 0;
if (innerSet != null) {
count = innerSet.size();
}
if (!ap.isCountValidForMultiplicity(count)) {
throw new JAvpNotAllowedException("AVP: " + ap + " has wrong count in message - " + (count), ap.getCode(), ap.getVendorId());
}
if (count != 0 && ap.isGrouped()) {
// we are grouped
validateGrouped(ap, innerSet);
}
}
}
/**
* @param ap
* @param innerSet
*/
private void validateGrouped(VAvpRepresentation ap, AvpSet innerSet) {
// we have set of grouped avps, and ap is grouped, lets validate
// NOTE this methods can be called multiple time, until we dont have
for (int index = 0; index < innerSet.size(); index++) {
Avp presumablyGrouped = innerSet.getAvpByIndex(index);
AvpSet groupedPart = null;
try {
groupedPart = presumablyGrouped.getGrouped();
} catch (AvpDataException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (groupedPart == null) {
log.error("Avp should be grouped, but its not, skipping validation: " + ap);
continue;
} else {
validateGroupedChildren(ap, groupedPart);
}
}
}
/**
* @param ap
* @param presumablyGrouped
*/
private void validateGroupedChildren(VAvpRepresentation ap, AvpSet groupedAvp) {
// we have grouped avp, and its representation, we should validate
// children.
for (VAvpRepresentation childrenVAvp : ap.getChildren()) {
AvpSet childSset = groupedAvp.getAvps(childrenVAvp.getCode(), childrenVAvp.getVendorId());
int count = childSset.size();
if (!childrenVAvp.isCountValidForMultiplicity(count)) {
throw new JAvpNotAllowedException("AVP: " + childrenVAvp + " has wrong count ,in grouped parent avp - " + (count)+", allowed: "+childrenVAvp.getMultiplicityIndicator(), ap.getCode(), ap.getVendorId());
}
if (childrenVAvp.isGrouped()) {
validateGrouped(childrenVAvp, childSset);
}
// else we are good ?
}
}
public void validate(AvpSet destination, Avp avp) {
VAvpRepresentation avpRep = new VAvpRepresentation(avp.getCode(), avp.getVendorId());
avpRep = this.messageAvps.get(avpRep);
if (avpRep == null)
return;
if (!avpRep.isAllowed()) {
throw new JAvpNotAllowedException("AVP: " + avpRep + " is not allowed.", avp.getCode(), avp.getVendorId());
}
// For avp beeing added :)
int count = 1;
AvpSet innerSet = destination.getAvps(avpRep.getCode(), avpRep.getVendorId());
if (innerSet != null) {
count += innerSet.size();
}
if (!avpRep.isCountValidForMultiplicity(count)) {
throw new JAvpNotAllowedException("AVP: " + avpRep + " is not allowed, to many avps present already - " + (count - 1)+", allowed: "+avpRep.getMultiplicityIndicator(), avp.getCode(), avp.getVendorId());
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Comparable#compareTo(java.lang.Object)
*/
public int compareTo(VMessageRepresentation o) {
if (o == this)
return 0;
if (o == null)
return 1;
return this.hashCode() - o.hashCode();
}
/**
* @param code
* @param vendorId
* @param count
* @return
*/
public boolean isCountValidForMultiplicity(int code, long vendorId, int count) {
VAvpRepresentation avpRep = new VAvpRepresentation(code, vendorId);
avpRep = this.messageAvps.get(avpRep);
if (avpRep == null)
return true;
return avpRep.isCountValidForMultiplicity(count);
}
/**
* @param code
* @param vendorId
* @return
*/
public boolean isAllowed(int code, long vendorId) {
VAvpRepresentation avpRep = new VAvpRepresentation(code, vendorId);
avpRep = this.messageAvps.get(avpRep);
if (avpRep == null)
return true;
return avpRep.isAllowed();
}
/**
* @param avpCode
* @param avpVendor
* @return
*/
public boolean hasRepresentation(int avpCode, long avpVendor) {
VAvpRepresentation avpRep = new VAvpRepresentation(avpCode, avpVendor);
avpRep = this.messageAvps.get(avpRep);
if (avpRep == null) {
return false;
} else {
return true;
}
}
@Override
public Object clone() throws CloneNotSupportedException {
VMessageRepresentation clone = (VMessageRepresentation) super.clone();
clone.applicationId = this.applicationId;
clone.commandCode = this.commandCode;
clone.isRequest = this.isRequest;
clone.name = this.name;
clone.messageAvps = new HashMap<VAvpRepresentation, VAvpRepresentation>();
for (VAvpRepresentation key : this.messageAvps.keySet()) {
clone.messageAvps.put((VAvpRepresentation) key.clone(), (VAvpRepresentation) this.messageAvps.get(key).clone());
}
return clone;
}
@Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append(isRequest ? "Request" : "Answer").append(" code: ").append(this.commandCode).append(" applicationId: ").append(this.applicationId).append(" name: ").append(this.name);
for (VAvpRepresentation childAvp : this.getMessageAvps().values()) {
sb.append("\n").append(childAvp.toString());
}
return sb.toString();
}
}