/*
* Mobicents, Communications Middleware
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser 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 Lesser General Public License
* for more details.
*
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
*
* Boston, MA 02110-1301 USA
*/
package org.jdiameter.common.impl.validation;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.jdiameter.api.Avp;
import org.jdiameter.api.AvpSet;
import org.jdiameter.api.Message;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Start time:11:42:36 2009-05-26<br>
* Project: diameter-parent<br>
*
* @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 DiameterMessageValidator {
private static final transient Logger log = LoggerFactory.getLogger(DiameterMessageValidator.class);
public static final String _AVP_ATTRIBUTE_NAME = "name";
public static final String _AVP_ATTRIBUTE_CODE = "code";
public static final String _AVP_ATTRIBUTE_VENDOR = "vendor";
public static final String _AVP_ATTRIBUTE_MULTIPLICITY = "multiplicity";
public static final String _AVP_ATTRIBUTE_INDEX = "index";
public static final String _VALIDATOR_NODE_NAME = "validator";
public static final String _VALIDATOR_NODE_ENABLED_ATTR = "enabled";
private static final DiameterMessageValidator instance = new DiameterMessageValidator();
private static final String fileName = "dictionary.xml";
private boolean on = true;
private boolean configured = false;
protected Map<VMessageRepresentation, VMessageRepresentation> commandMap = new HashMap<VMessageRepresentation, VMessageRepresentation>();
protected Map<VAvpRepresentation, VAvpRepresentation> avpMap = new HashMap<VAvpRepresentation, VAvpRepresentation>();
protected Map<String, String> vendorMap = new HashMap<String, String>();
protected Map<String, String> typedefMap = new HashMap<String, String>();
protected Map<String, VAvpRepresentation> nameToCodeMap = new TreeMap<String, VAvpRepresentation>(new Comparator<String>() {
public int compare(String o1, String o2) {
return (o1 == null) ? 1 : (o2 == null) ? -1 : o1.compareTo(o2);
}
});
/**
*
*/
protected DiameterMessageValidator() {
try {
InputStream is = DiameterMessageValidator.class.getClassLoader().getResourceAsStream(fileName);
if (is != null) {
parseConfiguration(is, false);
}
else {
log.debug("Unable to initialize validator with default filename ({} not found in classpath).", fileName);
}
}
catch (Exception e) {
log.error("Failed to init validator dictionary resources.", e);
}
}
public void parseConfiguration(InputStream is, boolean reset) {
long startTime = System.currentTimeMillis();
if (reset) {
this.configured = false;
this.commandMap.clear();
this.avpMap.clear();
this.vendorMap.clear();
this.typedefMap.clear();
this.nameToCodeMap.clear();
}
if (this.configured) {
return;
}
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
doc.getDocumentElement().normalize();
this.vendorMap = parseVendors(doc);
this.typedefMap = parseTypDefs(doc);
this.avpMap = parseAvps(doc, this.vendorMap);
this.resolveWeakGroupedChildren(this.avpMap, this.nameToCodeMap);
this.commandMap = parseCommands(doc, this.avpMap, this.nameToCodeMap);
this.configured = true;
NodeList validatorNodeList = doc.getElementsByTagName(_VALIDATOR_NODE_NAME);
if (validatorNodeList == null || validatorNodeList.getLength() == 0) {
this.on = false;
}
else {
boolean found = false;
for (int index = 0; index < validatorNodeList.getLength(); index++) {
if (validatorNodeList.item(index).getNodeType() == Node.ELEMENT_NODE) {
found = true;
Element validatorElement = (Element) validatorNodeList.item(index);
if (!validatorElement.hasAttribute(_VALIDATOR_NODE_ENABLED_ATTR)) {
this.on = false;
}
else {
this.on = Boolean.parseBoolean(validatorElement.getAttribute(_VALIDATOR_NODE_ENABLED_ATTR));
}
break;
}
}
if (!found) {
this.on = false;
}
}
long endTime = System.currentTimeMillis();
log.info("AVP Validator :: Loaded in {}ms == Vendors[{}] Commands[{}] Types[{}] AVPs[{}]", new Object[] { (endTime - startTime), vendorMap.size(), commandMap.size(), typedefMap.size(), avpMap.size() });
if (log.isInfoEnabled()) {
StringBuffer sb = new StringBuffer();
int c = 0;
for (VAvpRepresentation key : this.avpMap.keySet()) {
if (this.avpMap.get(key).isWeak()) {
c++;
sb.append("---------------------------------\n").append("Found incomplete AVP definition:\n").append(this.avpMap.get(key)).append("\n");
}
}
if(c > 0) {
sb.append("------- TOTAL INCOMPLETE AVPS COUNT: " + c + " -------");
log.info(sb.toString());
}
}
}
catch (Exception e) {
on = false;
log.error("Failed to parse validator configuration. Validator disabled.", e);
}
}
/**
* @param doc
* @param nameToCode
* @param avpMap
* @return
*/
private Map<VMessageRepresentation, VMessageRepresentation> parseCommands(Document doc, Map<VAvpRepresentation, VAvpRepresentation> avpMap, Map<String, VAvpRepresentation> nameToCodeMap) {
// here all grouped avps should have proper filling.
// now lets go through message definition, we have to respect
// application nodes
NodeList applicationNodes = doc.getElementsByTagName("application");
Map<VMessageRepresentation, VMessageRepresentation> commandMap = new HashMap<VMessageRepresentation, VMessageRepresentation>();
for (int applicationIndex = 0; applicationIndex < applicationNodes.getLength(); applicationIndex++) {
if (applicationNodes.item(applicationIndex).getNodeType() == Node.ELEMENT_NODE) {
Element applicationElement = (Element) applicationNodes.item(applicationIndex);
if (!applicationElement.hasAttribute("id")) {
log.error("Application definition does not have ID, skipping message");
continue;
}
long applicationCode = Long.valueOf(applicationElement.getAttribute("id"));
NodeList commandNodes = applicationElement.getElementsByTagName("command");
for (int c = 0; c < commandNodes.getLength(); c++) {
Node commandNode = commandNodes.item(c);
if (commandNode.getNodeType() == Node.ELEMENT_NODE) {
Element commandElement = (Element) commandNode;
// FIXME: add more
if (!commandElement.hasAttribute("request")) {
if (log.isDebugEnabled()) {
log.debug("Command for application: {} does not define if its request or answer, skipping.", applicationCode);
}
continue;
}
String commandName = commandElement.getAttribute("name");
String commandCode = commandElement.getAttribute("code");
// String commandVendorId =
// commandElement.getAttribute("vendor-id");
String isRequest = commandElement.getAttribute("request");
// FIXME: should commandVendorId should be used
// somewhere?
// String commandVendorCode =
// vendorMap.get(commandVendorId);
VMessageRepresentation msg = new VMessageRepresentation(Integer.valueOf(commandCode), applicationCode, Boolean.parseBoolean(isRequest), commandName);
Map<VAvpRepresentation, VAvpRepresentation> commandAvpList = new HashMap<VAvpRepresentation, VAvpRepresentation>();
msg.setMessageAvps(commandAvpList);
commandMap.put(msg, msg);
// now we have to process avp defs for this message :)
NodeList commandAvpsList = commandElement.getElementsByTagName("avp");
{
for (int commandAvpIndex = 0; commandAvpIndex < commandAvpsList.getLength(); commandAvpIndex++) {
if (commandAvpsList.item(commandAvpIndex).getNodeType() == Node.ELEMENT_NODE) {
Element commandAvpElement = (Element) commandAvpsList.item(commandAvpIndex);
String multiplicity = null;
String name = null;
String index = null;
if (!commandAvpElement.hasAttribute("name")) {
log.error("Command defines avp without name! Command: {}, Code: {}, ApplicationID: {}", new Object[] { msg.getName(), msg.getCommandCode(),
msg.getApplicationId() });
continue;
}
else {
name = commandAvpElement.getAttribute("name").trim();
}
if (!commandAvpElement.hasAttribute("multiplicity")) {
log.warn("Command defines avp without multiplicity.");
multiplicity = VAvpRepresentation._MP_ZERO_OR_MORE;
}
else {
multiplicity = commandAvpElement.getAttribute("multiplicity");
}
if (!commandAvpElement.hasAttribute("index")) {
index = "-1";
}
else {
index = commandAvpElement.getAttribute("index");
}
// here we have name and multiplicity. we
// have to get avp def from name, clone and
// set multiplicity.
VAvpRepresentation strongRepresentation = null;
VAvpRepresentation strongKey = nameToCodeMap.get(name.trim());
if (strongKey == null) {
log.warn("No strong avp key representation for msg, name: {}", name.trim());
continue;
}
strongRepresentation = this.avpMap.get(strongKey);
if (strongRepresentation != null && !strongRepresentation.isWeak()) {
VAvpRepresentation clone;
try {
clone = (VAvpRepresentation) strongRepresentation.clone();
clone.setMultiplicityIndicator(multiplicity);
clone.markFixPosition(Integer.valueOf(index));
commandAvpList.put(clone, clone);
}
catch (CloneNotSupportedException e) {
log.error("Unable to clone VAvpRepresentation", e);
}
}
else {
log.warn("No strong avp representation for msg: {}", strongKey);
}
}
}
}
}
}
}
}
return commandMap;
}
/**
* @param doc
* @param vendorMap
* @return
*/
public Map<VAvpRepresentation, VAvpRepresentation> parseAvps(Document doc, Map<String, String> vendorMap) {
// now, lets process avps, we ignore <application> boundries, since avps
// are unique by: name, code, vendor-name/mapped to id here
// once we have this set, we will resolve weak avps, than we can process
// messages, and based on avp name populate message with proper
// representations.
/**************************************************************************
* AVPs
*/
NodeList applicationNodes = doc.getElementsByTagName("application");
for (int index = 0; index < applicationNodes.getLength(); index++) {
Node n = applicationNodes.item(index);
if (n.getNodeType() != Node.ELEMENT_NODE) {
continue;
}
NodeList applicationChildElements = n.getChildNodes();
for (int applicationChildIndex = 0; applicationChildIndex < applicationChildElements.getLength(); applicationChildIndex++) {
Node avpNode = applicationChildElements.item(applicationChildIndex);
if (avpNode.getNodeType() == Node.ELEMENT_NODE && avpNode.getNodeName().trim().equals("avp")) {
Element avpElement = (Element) avpNode;
String avpName = avpElement.getAttribute("name").trim();
String avpDescription = avpElement.getAttribute("description");
String avpCode = avpElement.getAttribute("code");
String avpMayEncrypt = avpElement.getAttribute("may-encrypt");
String avpMandatory = avpElement.getAttribute("mandatory");
String avpProtected = avpElement.getAttribute("protected").equals("") ? "may" : avpElement.getAttribute("protected");
String avpVendorBit = avpElement.getAttribute("vendor-bit");
String avpVendorId = avpElement.getAttribute("vendor-id");
long vendorCode = getVendorCode(avpVendorId, vendorMap);
String avpConstrained = avpElement.getAttribute("constrained");
// So it shows, clearly we mess up some where.
String avpType = "NOT-SET";
List<VAvpRepresentation> weakGroupedAvpChildren = new ArrayList<VAvpRepresentation>();
// Now either we have type or grouped
NodeList avpChildNodes = avpNode.getChildNodes();
for (int j = 0; j < avpChildNodes.getLength(); j++) {
Node avpChildNode = avpChildNodes.item(j);
if (avpChildNode.getNodeType() == Node.ELEMENT_NODE) {
Element avpChildElement = (Element) avpChildNode;
if (avpChildElement.getNodeName().equals("grouped")) {
// All we need to know is that's a grouped AVP.
avpType = "Grouped";
// we ceate a bunch on weak avp reps.
NodeList groupedAvpMembers = avpChildElement.getChildNodes();
for (int gChildIndex = 0; gChildIndex < groupedAvpMembers.getLength(); gChildIndex++) {
Node groupedAvpChildNode = groupedAvpMembers.item(gChildIndex);
if (groupedAvpChildNode.getNodeType() == Node.ELEMENT_NODE) {
// we have our member
Element groupedChildWeakElement = (Element) groupedAvpChildNode;
String name = null;
String multiplicity = VAvpRepresentation._MP_ZERO_OR_MORE;
String indexIndicator = "-1";
if (!groupedChildWeakElement.hasAttribute("name")) {
log.error("Grouped child does not have name, grouped avp: Name[" + avpName + "] Description[" + avpDescription + "] Code[" + avpCode + "] May-Encrypt["
+ avpMayEncrypt + "] Mandatory[" + avpMandatory + "] Protected [" + avpProtected + "] Vendor-Bit [" + avpVendorBit + "] Vendor-Id [" + avpVendorId
+ "] Constrained[" + avpConstrained + "] Type [" + avpType + "]");
continue;
}
else {
name = groupedChildWeakElement.getAttribute("name").trim();
}
if (!groupedChildWeakElement.hasAttribute("multiplicity")) {
multiplicity = VAvpRepresentation._MP_ZERO_OR_MORE;
}
else {
multiplicity = groupedChildWeakElement.getAttribute("multiplicity");
}
if (!groupedChildWeakElement.hasAttribute("index")) {
indexIndicator = "-1";
}
else {
indexIndicator = groupedChildWeakElement.getAttribute("index");
}
VAvpRepresentation weakChild = new VAvpRepresentation(name, vendorCode);
weakChild.setMultiplicityIndicator(multiplicity);
weakChild.markFixPosition(Integer.valueOf(indexIndicator));
// just to be sure
weakChild.markWeak(true);
weakGroupedAvpChildren.add(weakChild);
}
}
}
else if (avpChildElement.getNodeName().equals("type")) {
avpType = avpChildElement.getAttribute("type-name");
avpType = typedefMap.get(avpType);
}
else if (avpChildElement.getNodeName().equals("enum")) {
// NOP?
}
}
}
if (log.isDebugEnabled()) {
log.debug("Parsed AVP: Name[" + avpName + "] Description[" + avpDescription + "] Code[" + avpCode + "] May-Encrypt[" + avpMayEncrypt + "] Mandatory[" + avpMandatory
+ "] Protected [" + avpProtected + "] Vendor-Bit [" + avpVendorBit + "] Vendor-Id [" + avpVendorId + "] Constrained[" + avpConstrained + "] Type [" + avpType + "]");
}
try {
VAvpRepresentation avp = null;
avp = new VAvpRepresentation(avpName.trim(), avpDescription, Integer.valueOf(avpCode), avpMayEncrypt.equals("yes"), avpMandatory, avpProtected, avpVendorBit, vendorCode,
avpConstrained.equals("true"), avpType);
if (avp.isGrouped()) {
avp.setChildren(weakGroupedAvpChildren);
// we are not strong enough., children are referenced ONLY by name, so we are
// weak until all children can be resolved to strong representation
avp.markWeak(true);
}
VAvpRepresentation mapKey = new VAvpRepresentation(avp.getCode(), avp.getVendorId());
avpMap.put(mapKey, avp);
if(nameToCodeMap.containsKey(avp.getName().trim()) && log.isErrorEnabled()) {
log.error("Overwriting definition of avp(same name) , present: {}, new one: {}",new Object[]{nameToCodeMap.get(avp.getName().trim()),mapKey});
}
nameToCodeMap.put(avp.getName().trim(), mapKey);
}
catch (Exception e) {
if (log.isErrorEnabled()) {
log.error("Failed Parsing AVP: Name[" + avpName + "] Description[" + avpDescription + "] Code[" + avpCode + "] May-Encrypt[" + avpMayEncrypt + "] Mandatory["
+ avpMandatory + "] Protected [" + avpProtected + "] Vendor-Bit [" + avpVendorBit + "] Vendor-Id [" + avpVendorId + "] Constrained[" + avpConstrained + "] Type ["
+ avpType + "]", e);
}
}
}
}
}
return avpMap;
}
/**
* @param doc
* @return
*/
public Map<String, String> parseTypDefs(Document doc) {
// here we have full base of vendor-name --> vendorId(long) map.
// Now lets parse type defs, dunno why, but we do that, so we can std out it :)
/*
* <typedefn type-name="OctetString"/> <typedefn type-name="UTF8String"
* type-parent="OctetString"/> <typedefn type-name="VendorId"
* type-parent="Unsigned32"/>
*/
NodeList typedefNodes = doc.getElementsByTagName("typedefn");
HashMap<String, String> typedefMap = new HashMap<String, String>();
for (int td = 0; td < typedefNodes.getLength(); td++) {
Node typedefNode = typedefNodes.item(td);
if (typedefNode.getNodeType() == Node.ELEMENT_NODE) {
Element typedefElement = (Element) typedefNode;
String typeName = typedefElement.getAttribute("type-name");
String typeParent = typedefElement.getAttribute("type-parent");
if (typeParent.equals("") || typeName.equals("UTF8String")) {
typeParent = typeName;
}
typedefMap.put(typeName, typeParent);
}
}
return typedefMap;
}
/**
* @param doc
* @return
*/
public Map<String, String> parseVendors(Document doc) {
// Parse vendors, we will need those.
/*
* <!-- ************************* Vendors ****************************
* --> <vendor vendor-id="None" code="0" name="None"/> <vendor
* vendor-id="HP" code="11" name="Hewlett Packard"/> <vendor
* vendor-id="Merit" code="61" name="Merit Networks"/> <vendor
* vendor-id="Sun" code="42" name="Sun Microsystems, Inc."/> <vendor
* vendor-id="USR" code="429" name="US Robotics Corp."/> <vendor
* vendor-id="3GPP2" code="5535" name="3GPP2"/> <vendor vendor-id="TGPP"
* code="10415" name="3GPP"/> <vendor vendor-id="TGPPCX" code="16777216"
* name="3GPP CX/DX"/> <vendor vendor-id="Ericsson" code="193"
* name="Ericsson"/> <vendor vendor-id="ETSI" code="13019" name="ETSI"/>
* <vendor vendor-id="Vodafone" code="12645" name="Vodafone"/> <!--
* *********************** End Vendors ************************** -->
*/
HashMap<String, String> vendorMap = new HashMap<String, String>();
NodeList vendorNodes = doc.getElementsByTagName("vendor");
for (int v = 0; v < vendorNodes.getLength(); v++) {
Node vendorNode = vendorNodes.item(v);
if (vendorNode.getNodeType() == Node.ELEMENT_NODE) {
Element vendorElement = (Element) vendorNode;
String vendorCode = vendorElement.getAttribute("code");
String vendorId = vendorElement.getAttribute("vendor-id");
vendorMap.put(vendorId, vendorCode);
}
}
return vendorMap;
}
public void resolveWeakGroupedChildren(Map<VAvpRepresentation, VAvpRepresentation> avpMap, Map<String, VAvpRepresentation> nameToCodeMap) {
// FIXME: we have maximum 50 runs, this does not take much time, limits
// number of iterations over collection to fill all data.
// this is due uncertanity - that data might have not been initialized
// yet - but its somewhere in collections
int runCount = 20;
boolean haveWeaklings = true;
while (haveWeaklings && runCount > 0) {
boolean passed = true;
for (VAvpRepresentation groupedAvp : avpMap.values()) {
if (!groupedAvp.isGrouped() || !groupedAvp.isWeak()) {
continue;
}
if (resolveWeaklings(groupedAvp, avpMap, nameToCodeMap)) {
passed = false;
}
else {
// NOP?
}
}
if (passed) {
haveWeaklings = false;
}
runCount--;
}
}
/**
* @param groupedAvp
* @return
*/
protected boolean resolveWeaklings(VAvpRepresentation groupedAvp, Map<VAvpRepresentation, VAvpRepresentation> avpMap, Map<String, VAvpRepresentation> nameToCodeMap) {
// if we are here it means this avp rep is weak. its grouped for sure.
boolean hasWeaklings = false;
List<VAvpRepresentation> children = groupedAvp.getChildren();
for (int index = 0; index < children.size(); index++) {
VAvpRepresentation local = (VAvpRepresentation) children.get(index);
if (local.isWeak()) {
// we shoud have strong rep somewhere.
// AvpKey strongKey = new AvpKey(local.getCode(),
// local.getVendorId());
VAvpRepresentation strongRep = null;
VAvpRepresentation strongKey = nameToCodeMap.get(local.getName().trim());
if (strongKey == null) {
log.debug("No avp key representation for avp name: {}", local.getName().trim());
hasWeaklings = true;
continue;
}
strongRep = avpMap.get(strongKey);
if (strongRep == null || strongRep.isWeak()) {
log.debug("Resolving weak link for: {}; Strong representation for name: {} does not exist V:[{}]!", new Object[] { groupedAvp, local.getName(), strongRep });
hasWeaklings = true;
}
else {
try {
strongRep = (VAvpRepresentation) strongRep.clone();
}
catch (CloneNotSupportedException e) {
log.error("Unable to clone VAvpRepresentation", e);
}
strongRep.setMultiplicityIndicator(local.getMultiplicityIndicator());
children.remove(index);
children.add(index, strongRep);
}
}
else {
continue;
}
}
if (!hasWeaklings) {
groupedAvp.markWeak(false);
}
return hasWeaklings;
}
public long getVendorCode(String vendorId, Map<String, String> vendorMap) {
long value = -1;
if (vendorId == null) {
value = 0;
}
else {
String vendorCode = vendorMap.get(vendorId);
value = vendorCode == null ? 0 : Long.parseLong(vendorCode);
}
return value;
}
/**
* Retrieves singleton instance of DiameterMessageValidator
*
* @return
*/
public static final DiameterMessageValidator getInstance() {
return DiameterMessageValidator.instance;
}
/**
* Determines if validator is enabled.
*
* @return <ul>
* <li><b>true</b> if validator is enabled</li>
* <li><b>false</b> if validator is disabled</li>
* </ul>
*/
public boolean isOn() {
return on;
}
/**
* Valdiates message against XML configuration file. If there is no
* representation it does nothing. If
* {@link DiameterMessageValidator#hasRepresentation(int, long, boolean, int, long)}
* returns false this method returns always without exception.
*
* @param msg
* @throws JAvpNotAllowedException
* - thrown when validation fails.
*/
public void validate(Message msg) throws JAvpNotAllowedException {
if (!on) {
return; // throw new IllegalStateException("validation is of.");
}
VMessageRepresentation rep = new VMessageRepresentation(msg.getCommandCode(), msg.getApplicationId(), msg.isRequest());
rep = this.commandMap.get(rep);
if (rep == null) {
// no notion, lets leave it.
log.warn("Validation could not be performed for Command. Code={}, Application-Id={}, Req={}", new Object[] { msg.getCommandCode(), msg.getApplicationId(), msg.isRequest() });
return;
}
rep.validate(msg);
}
/**
* Validate if avp can be added/present in message - meaning it checks if
* there is place for passed avp. If
* {@link DiameterMessageValidator#hasRepresentation(int, long, boolean, int, long)}
* returns false this method returns always without exception.
*
* @param commandCode
* - message command code
* @param appId
* - application id of message
* @param isRequest
* - true if message is request.
* @param destination
* - AvpSet of message
* @param avp
* - avp to be checked.
*/
public void validate(int commandCode, long appId, boolean isRequest, AvpSet destination, Avp avp) {
if (!on)
throw new IllegalStateException("validation is of.");
VMessageRepresentation rep = new VMessageRepresentation(commandCode, appId, isRequest);
rep = this.commandMap.get(rep);
if (rep == null) {
// no notion, lets leave it.
return;
}
rep.validate(destination, avp);
}
/**
* Determines if avp identified by code and vendor has correct multiplicity
* in passed set. If
* {@link DiameterMessageValidator#hasRepresentation(int, long, boolean, int, long)}
* returns false this method returns always true.
*
* @param commandCode
* - message code
* @param appId
* - message application id.
* @param isRequest
* - true if message is request.
* @param destination
* - message AvpSet
* @param avpCode
* - avp code
* @param avpVendor
* - avp vendor - zero if there is none
* @return<ul> <li><b>true</b> if multiplicity is correct</li> <li>
* <b>false</b> if multiplicity is incorrect</li> </ul>
*/
public boolean isCountValidForMultiplicity(int commandCode, long appId, boolean isRequest, AvpSet destination, int avpCode, long avpVendor) {
if (!on)
throw new IllegalStateException("validation is of.");
VMessageRepresentation rep = new VMessageRepresentation(commandCode, appId, isRequest);
rep = this.commandMap.get(rep);
if (rep == null) {
// no notion, lets leave it.
return true;
}
AvpSet innerSet = destination.getAvps(avpCode, avpVendor);
// FIXME: 1 is for avp beeing added
int count = 1;
if (innerSet != null) {
count += innerSet.size();
}
return rep.isCountValidForMultiplicity(avpCode, avpVendor, count);
}
/**
* Determines if avp is allowed in message. If
* {@link DiameterMessageValidator#hasRepresentation(int, long, boolean, int, long)}
* returns false this method returns always true.
*
* @param commandCode
* - message command code
* @param appId
* - message application id
* @param isRequest
* - true if message is request.
* @param avpCode
* - avp code.
* @param avpVendor
* - avp vendor, zero if none.
* @return
*/
public boolean isAllowed(int commandCode, long appId, boolean isRequest, int avpCode, long avpVendor) {
if (!on)
throw new IllegalStateException("Message validation is disabled.");
VMessageRepresentation rep = new VMessageRepresentation(commandCode, appId, isRequest);
rep = this.commandMap.get(rep);
// if null, no notion, lets leave it.
return rep == null ? true : rep.isAllowed(avpCode, avpVendor);
}
/**
* Return values is computed as follows:<br>
* return messages.get(commandCode, appId, isRequest)!=null &&
* messages.get(commandCode , appId, isRequest).getAvp(avpCode,
* avpVendor)!=null;
*
* @param commandCode
* - message command code
* @param appId
* - message application id
* @param isRequest
* - true if message is request.
* @param avpCode
* - avp code.
* @param avpVendor
* - avp vendor, zero if none.
* @return
*/
public boolean hasRepresentation(int commandCode, long appId, boolean isRequest, int avpCode, long avpVendor) {
VMessageRepresentation rep = new VMessageRepresentation(commandCode, appId, isRequest);
rep = this.commandMap.get(rep);
return rep == null ? false : rep.hasRepresentation(avpCode, avpVendor);
}
// SETTER GETTER SECTION -- allows to change configuration
// FIXME: add clone ops
public Map<VMessageRepresentation, VMessageRepresentation> getCommandMap() {
return commandMap;
}
public void setCommandMap(Map<VMessageRepresentation, VMessageRepresentation> commandMap) {
this.commandMap = commandMap;
}
public Map<VAvpRepresentation, VAvpRepresentation> getAvpMap() {
return avpMap;
}
public void setAvpMap(Map<VAvpRepresentation, VAvpRepresentation> avpMap) {
this.avpMap = avpMap;
}
public Map<String, String> getVendorMap() {
return vendorMap;
}
public void setVendorMap(Map<String, String> vendorMap) {
this.vendorMap = vendorMap;
}
public Map<String, String> getTypedefMap() {
return typedefMap;
}
public void setTypedefMap(Map<String, String> typedefMap) {
this.typedefMap = typedefMap;
}
public Map<String, VAvpRepresentation> getNameToCodeMap() {
return nameToCodeMap;
}
public void setNameToCodeMap(Map<String, VAvpRepresentation> nameToCodeMap) {
this.nameToCodeMap = nameToCodeMap;
}
public boolean isConfigured() {
return configured;
}
}