/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2016, TeleStax Inc. and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* JBoss, Home of Professional Open Source
* Copyright 2007-2011, Red Hat, Inc. and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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 software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jdiameter.common.impl.validation;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
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.Message;
import org.jdiameter.api.validation.AvpNotAllowedException;
import org.jdiameter.api.validation.AvpRepresentation;
import org.jdiameter.api.validation.Dictionary;
import org.jdiameter.api.validation.MessageRepresentation;
import org.jdiameter.api.validation.ValidatorLevel;
import org.jdiameter.client.impl.DictionarySingleton;
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;
/**
* Implementation of {@link Dictionary} interface.
*
* @author <a href="mailto:baranowb@gmail.com"> Bartosz Baranowski </a>
* @author <a href="mailto:brainslog@gmail.com"> Alexandre Mendonca </a>
* @since 1.5.4.0-build404
*/
public class DictionaryImpl implements Dictionary {
private static transient Logger logger = LoggerFactory.getLogger(DictionaryImpl.class);
public static final Dictionary INSTANCE = new DictionaryImpl("dictionary.xml");
private static final String UNDEFINED_AVP_TYPE = "UNDEFINED";
private static final String AVP_DEFAULT_INDEX = "-1";
private static final String AVP_DEFAULT_MULTIPLICITY = AvpRepresentation._MP_ZERO_OR_MORE;
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";
private Map<AvpRepresentation, AvpRepresentation> avpMap = new HashMap<AvpRepresentation, AvpRepresentation>();
private Map<String, AvpRepresentation> avpByNameMap = new HashMap<String, AvpRepresentation>();
private Map<String, String> vendorMap = new HashMap<String, String>();
private Map<MessageRepresentation, MessageRepresentation> commandMap = new HashMap<MessageRepresentation, MessageRepresentation>();
private Map<String, String> typedefMap = new HashMap<String, String>();
private boolean configured = false;
private DictionaryImpl(String confFile) {
this.init(confFile);
}
private void init(String confFile) {
InputStream is = null;
try {
is = DictionarySingleton.class.getResourceAsStream(confFile);
if (is == null) {
logger.debug("Failed to locate dictionary configuration file: {}, in class classloader. Trying thread context class loader.", confFile);
is = Thread.currentThread().getContextClassLoader().getResourceAsStream(confFile);
}
if (is == null) {
logger.debug("Failed to locate dictionary configuration file: {}, in thread context class loader. Trying using 'config/' prefix.", confFile);
is = Thread.currentThread().getContextClassLoader().getResourceAsStream("config/" + confFile);
}
if (is == null) {
logger.debug("Failed to locate dictionary configuration file: {}, in thread context class loader. Trying regular file.", confFile);
File fDict = new File(confFile);
if (fDict.exists()) {
is = new FileInputStream(fDict);
}
else {
logger.debug("Failed to locate dictionary configuration file: {}, from regular file. Trying using 'config/' prefix.", confFile);
fDict = new File("config/" + confFile);
if (fDict.exists()) {
is = new FileInputStream(fDict);
}
}
}
if (is != null) {
this.configure(is);
}
else {
this.setEnabled(false);
logger.warn("Failed to initialize and configure Diameter Dictionary since configuration file was not found. Validator is disabled.");
}
}
catch (FileNotFoundException fnfe) {
logger.debug("Could not load configuration file: {}, from any known location.", confFile);
}
finally {
if (is != null) {
try {
is.close();
}
catch (IOException e) {
logger.error("", e);
}
}
}
}
// Parser functions ---------------------------------------------------------
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#configure(java.io.InputStream)
*/
@Override
public void configure(InputStream is) {
if (is == null) {
logger.error("No input stream to configure dictionary from?");
return;
}
try {
long startTime = System.currentTimeMillis();
this.avpByNameMap = new TreeMap<String, AvpRepresentation>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return (o1 == null) ? 1 : (o2 == null) ? -1 : o1.compareTo(o2);
}
});
this.vendorMap = new HashMap<String, String>();
this.typedefMap = new HashMap<String, String>();
this.avpMap = new HashMap<AvpRepresentation, AvpRepresentation>();
this.commandMap = new HashMap<MessageRepresentation, MessageRepresentation>();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
doc.getDocumentElement().normalize();
this.parseVendors(doc);
this.parseTypeDefs(doc);
this.parseAvps(doc);
this.parseCommands(doc);
this.configured = true;
long endTime = System.currentTimeMillis();
if (logger.isInfoEnabled()) {
logger.info("Mobicents Diameter Dictionary loaded in {}ms -- Vendors[{}] Commands[{}] Types[{}] AVPs[{}]",
new Object[] { (endTime - startTime), vendorMap.size(), commandMap.size(), typedefMap.size(), avpMap.size() });
}
if (logger.isInfoEnabled()) {
StringBuffer sb = new StringBuffer();
int c = 0;
for (AvpRepresentation 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: ").append(c).append(" -------");
logger.info(sb.toString());
}
}
}
catch (Exception e) {
this.enabled = false;
this.configured = false;
logger.error("Failed to parse validator configuration. Validator disabled.", e);
}
finally {
// close?
try {
is.close();
}
catch (IOException e) {
logger.debug("Failed to close InputStream for Dictionary XML.", e);
}
}
}
/**
* Parses the <vendor /> attributes from a Dictionary XML Document
*
* @param doc the DOM object representing the XML Document with the Dictionary definitions
*/
protected void parseVendors(Document doc) {
// Parse vendors, we will need those.
// Format: <vendor vendor-id="TGPP" code="10415" name="3GPP" />
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;
// Get the Code (number) and ID (string)
String vendorCode = vendorElement.getAttribute("code");
String vendorId = vendorElement.getAttribute("vendor-id");
vendorMap.put(vendorId, vendorCode);
}
}
}
/**
* Parses the <typedefn /> attributes from a Dictionary XML Document
*
* @param doc the DOM object representing the XML Document with the Dictionary definitions
*/
protected void parseTypeDefs(Document doc) {
// Parse type definitions. Handy to match against defined AVP types
// and to fill AVPs with generic function.
// Format: <typedefn type-name="Integer32" />
// <typedefn type-name="Enumerated" type-parent="Integer32" />
NodeList typedefNodes = doc.getElementsByTagName("typedefn");
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");
// UTF8String and Time are special situations, we don't want to convert these.
if (typeParent == null || typeParent.equals("") || typeName.equals("UTF8String") || typeName.equals("Time")) {
typeParent = typeName;
}
typedefMap.put(typeName, typeParent);
}
}
}
/**
* Parses the <typedefn /> attributes from a Dictionary XML Document
*
* @param doc the DOM object representing the XML Document with the Dictionary definitions
*/
protected void parseAvps(Document doc) {
// Format: <avpdefn name="Talk-Burst-Volume" code="1256" vendor-id="TGPP" mandatory="must" protected="may" may-encrypt="true" vendor-bit="must" >
// <type type-name="Unsigned32" />
// </avpdefn>
NodeList avpDefnNodes = doc.getElementsByTagName("avpdefn");
for (int i = 0; i < avpDefnNodes.getLength(); i++) {
Node avpNode = avpDefnNodes.item(i);
Element avpDefnElement = (Element) avpNode;
String avpName = avpDefnElement.getAttribute("name");
String avpCode = avpDefnElement.getAttribute("code");
String avpVendorId = avpDefnElement.getAttribute("vendor-id");
String avpMandatory = avpDefnElement.getAttribute("mandatory");
String avpProtected = avpDefnElement.getAttribute("protected").equals("") ? "may" : avpDefnElement.getAttribute("protected");
String avpMayEncrypt = avpDefnElement.getAttribute("may-encrypt");
String avpVendorBit = avpDefnElement.getAttribute("vendor-bit");
long vendorCode = getVendorCode(avpVendorId);
// Let's figure out the type
// It can be:
// <type type-name="UTF8String" />
// OR
// <grouped> <avp name="PoC-Change-Time" multiplicity="1" /> ... </grouped>
// OR
// <type type-name="Enumerated"> <enum code="0" name="MULTICAST" /> ... </enumerated>
String avpOriginalType = UNDEFINED_AVP_TYPE;
String avpType = avpOriginalType;
List<AvpRepresentation> groupedAvpChilds = new ArrayList<AvpRepresentation>();
NodeList avpDefnChildNodes = avpNode.getChildNodes();
for (int j = 0; j < avpDefnChildNodes.getLength(); j++) {
Node avpDefnChildNode = avpDefnChildNodes.item(j);
if (avpDefnChildNode.getNodeType() == Node.ELEMENT_NODE) {
Element avpDefnChildElement = (Element) avpDefnChildNode;
if (avpDefnChildElement.getNodeName().equals("grouped")) {
avpOriginalType = "Grouped";
avpType = avpOriginalType;
// Let's fetch the childs
// Format: <avp name="PoC-Change-Time" multiplicity="1" />
NodeList groupedAvpMembers = avpDefnChildElement.getChildNodes();
for (int gChildIndex = 0; gChildIndex < groupedAvpMembers.getLength(); gChildIndex++) {
Node groupedAvpChildNode = groupedAvpMembers.item(gChildIndex);
if (groupedAvpChildNode.getNodeType() == Node.ELEMENT_NODE) {
Element groupedAvpChildElement = (Element) groupedAvpChildNode;
String childName = null;
String childMultiplicity = AVP_DEFAULT_MULTIPLICITY;
String childIndexIndicator = AVP_DEFAULT_INDEX;
if (!groupedAvpChildElement.hasAttribute("name")) {
if (logger.isDebugEnabled()) {
logger.debug(new StringBuffer("[ERROR] Grouped child does not have name, grouped avp: Name[").append(avpName).append("] Description[")
.append("").append("] Code[").append(avpCode).append("] May-Encrypt[").append(avpMayEncrypt).append("] Mandatory[")
.append(avpMandatory).append("] Protected [").append(avpProtected).append("] Vendor-Bit [").append(avpVendorBit).append("] Vendor-Id [")
.append(avpVendorId).append("] Constrained[").append("").append("] Type [").append(avpType).append("]").toString());
}
continue;
}
else {
childName = groupedAvpChildElement.getAttribute("name");
}
childMultiplicity = groupedAvpChildElement.hasAttribute("multiplicity") ?
groupedAvpChildElement.getAttribute("multiplicity") : AvpRepresentation._MP_ZERO_OR_MORE;
childIndexIndicator = groupedAvpChildElement.hasAttribute("index") ?
groupedAvpChildElement.getAttribute("index") : "-1";
// have we parsed this child definition already?
AvpRepresentation childRep = this.avpByNameMap.get(childName);
AvpRepresentationImpl child = null;
if (childRep != null) {
try {
child = (AvpRepresentationImpl) childRep.clone();
}
catch (CloneNotSupportedException cnse) {
// It should not happen, but anyway
if (logger.isWarnEnabled()) {
logger.warn("Unable to clone AVP " + childRep, cnse);
}
}
}
else {
child = new AvpRepresentationImpl(childName, vendorCode);
child.markWeak(true);
}
child.setMultiplicityIndicator(childMultiplicity);
child.markFixPosition(Integer.valueOf(childIndexIndicator));
groupedAvpChilds.add(child);
}
}
}
else if (avpDefnChildElement.getNodeName().equals("type")) {
avpOriginalType = avpDefnChildElement.getAttribute("type-name");
avpType = avpOriginalType;
//FIXME: baranowb: why this is like that? This changes type of AVP to primitive ONE..? Checks against type dont make sense, ie to check for Address type...
avpType = typedefMap.get(avpType);
if (avpType == null) {
logger.warn("Unknown AVP Type ({}) for AVP with code {} and vendor-id {} ",
new Object[] { avpDefnChildElement.getAttribute("type-name"), avpCode, avpVendorId});
}
}
else {
logger.warn("Unknown AVP Definition child element for AVP with code {} and vendor-id {} ", avpCode, avpVendorId);
}
}
}
try {
AvpRepresentationImpl avp = null;
avp = new AvpRepresentationImpl(avpName, "N/A", Integer.valueOf(avpCode), avpMayEncrypt.equals("yes"), avpMandatory,
avpProtected, avpVendorBit, vendorCode, avpOriginalType, avpType);
if (avp.isGrouped()) {
avp.setChildren(groupedAvpChilds);
// 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);
}
resolveWeakLinks(avp);
AvpRepresentation existingAvp = null;
if ((existingAvp = avpMap.get(avp)) != null) {
logger.warn("Duplicated AVP Definition for AVP Code: {}, Vendor-Id: {}. See TRACE logs for definitions.", avp.getCode(), avp.getVendorId());
logger.trace("Existing AVP:\r\n {}\r\n New AVP:\r\n {}", existingAvp, avp);
}
else {
avpMap.put(avp, avp);
}
AvpRepresentation oldAvp = avpByNameMap.put(avp.getName(), avp);
if (oldAvp != null) {
logger.debug("[WARN] Overwrited definition of AVP with the same name: Old: {}, New: {}", new Object[] { oldAvp, avp });
}
}
catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug(new StringBuffer("[ERROR] Failed Parsing AVP: Name[").append(avpName).append("] Description[").append("N/A").
append("] Code[").append(avpCode).append("] May-Encrypt[").append(avpMayEncrypt).append("] Mandatory[").append(avpMandatory).
append("] Protected [").append(avpProtected).append("] Vendor-Bit [").append(avpVendorBit).append("] Vendor-Id [").append(avpVendorId).
append("] Constrained[").append("N/A").append("] OriginalType [").append(avpOriginalType).
append("] Type [").append(avpType).append("]").toString(), e);
}
}
}
for (AvpRepresentation rep : avpMap.values()) {
markWeaks((AvpRepresentationImpl) rep);
}
}
private boolean markWeaks(AvpRepresentationImpl rep) {
if (rep.isGrouped()) {
boolean isWeak = false;
for (AvpRepresentation repC : rep.getChildren()) {
if (markWeaks((AvpRepresentationImpl) repC)) {
isWeak = true;
}
}
rep.markWeak(isWeak);
}
else {
rep.markWeak(rep.getCode() == -1);
}
return rep.isWeak();
}
/**
* For a given AVP resolves the weak links (where AVP definition in grouped
* AVPs is not yet known, and only added by Name)
*
* @param newAvp the AVP which was just defined
*/
private void resolveWeakLinks(AvpRepresentation newAvp) {
for (AvpRepresentation avp : avpMap.values()) {
if (avp.isGrouped()) {
if (avp.getName().equals(newAvp.getName())) {
continue;
}
List<AvpRepresentation> avpChilds = avp.getChildren();
for (int n = 0; n < avpChilds.size(); n++) {
AvpRepresentation avpChild = avpChilds.get(n);
if (avpChild.getName().equals(newAvp.getName())) {
try {
AvpRepresentationImpl strongAvp = (AvpRepresentationImpl) newAvp.clone();
strongAvp.setMultiplicityIndicator(avpChild.getMultiplicityIndicator());
strongAvp.markFixPosition(avpChild.getPositionIndex());
strongAvp.markWeak(false);
avpChilds.set(n, strongAvp);
resolveWeakLinks(avp);
}
catch (CloneNotSupportedException cnse) {
// It should not happen, but anyway
if (logger.isWarnEnabled()) {
logger.warn("Unable to clone AVP " + newAvp, cnse);
}
}
}
}
}
}
}
/**
* @param doc
* @param nameToCode
* @param avpMap
* @return
*/
private void parseCommands(Document doc) {
// 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<MessageRepresentation, MessageRepresentation> commandMap = new
// HashMap<MessageRepresentation, MessageRepresentation>();
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")) {
logger.debug("[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;
if (!commandElement.hasAttribute("request")) {
logger.debug("[ERROR] 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 isRequest = commandElement.getAttribute("request");
MessageRepresentationImpl msg = new MessageRepresentationImpl(Integer.valueOf(commandCode), applicationCode,
Boolean.parseBoolean(isRequest), commandName);
Map<AvpRepresentation, AvpRepresentation> commandAvpList = new HashMap<AvpRepresentation, AvpRepresentation>();
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")) {
logger.debug("[ERROR] Command defines avp without name! Command: {}, Code: {}, ApplicationID: {}",
new Object[] { msg.getName(), msg.getCommandCode(), msg.getApplicationId() });
continue;
}
else {
name = commandAvpElement.getAttribute("name");
}
if (!commandAvpElement.hasAttribute("multiplicity")) {
logger.debug("[WARN] Command defines avp without multiplicity.");
multiplicity = AvpRepresentation._MP_ZERO_OR_MORE;
}
else {
multiplicity = commandAvpElement.getAttribute("multiplicity");
}
index = commandAvpElement.hasAttribute("index") ? commandAvpElement.getAttribute("index") : "-1";
String avpCode = commandAvpElement.getAttribute("code");
String avpVendor = commandAvpElement.getAttribute("vendor");
if (avpCode == null) {
logger.debug("[ERROR] Command defines avp without code! Command: {}, Code: {}, ApplicationID: {}",
new Object[] { msg.getName(), msg.getCommandCode(), msg.getApplicationId() });
continue;
}
if (avpVendor == null) {
logger.debug("[WARN] Command defines avp without vendor, assuming default. Command: {}, Code: {}, ApplicationID: {}",
new Object[] { msg.getName(), msg.getCommandCode(), msg.getApplicationId() });
avpVendor = "0";
}
// here we have name and multiplicity. we have to get avp def from name, clone and set multiplicity.
AvpRepresentation strongRepresentation = null;
AvpRepresentation strongKey = getMapKey(Integer.valueOf(avpCode), Long.valueOf(avpVendor));
strongRepresentation = this.avpMap.get(strongKey);
if (strongRepresentation != null && !strongRepresentation.isWeak()) {
AvpRepresentationImpl clone;
try {
clone = (AvpRepresentationImpl) strongRepresentation.clone();
clone.setMultiplicityIndicator(multiplicity);
clone.markFixPosition(Integer.valueOf(index));
commandAvpList.put(clone, clone);
}
catch (CloneNotSupportedException cnse) {
// It should not happen, but anyway
if (logger.isWarnEnabled()) {
logger.warn("Unable to clone AVP " + strongRepresentation, cnse);
}
}
}
else {
logger.debug("[WARN] No strong avp for key {}, in name: {}", new Object[] {strongKey, name});
continue;
}
}
}
msg.setMessageAvps(commandAvpList);
}
}
}
}
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#isConfigured()
*/
@Override
public boolean isConfigured() {
return this.configured;
}
@Override
public AvpRepresentation getAvp(int code) {
return getAvp(code, 0);
}
@Override
public AvpRepresentation getAvp(int code, long vendorId) {
if (!this.configured) {
return null;
}
AvpRepresentation avp = avpMap.get(getMapKey(code, vendorId));
if (avp == null) {
logger.warn("AVP with code {} and Vendor-Id {} not present in dictionary!", code, vendorId);
}
return avp;
}
@Override
public AvpRepresentation getAvp(String avpName) {
return this.configured ? avpByNameMap.get(avpName) : null;
}
private long getVendorCode(String vendorId) {
long value = -1;
if (vendorId == null) {
value = 0;
}
else {
String vendorCode = vendorMap.get(vendorId);
value = vendorCode == null ? 0 : Long.parseLong(vendorCode);
}
return value;
}
private AvpRepresentation getMapKey(int avpCode, long vendorId) {
return new AvpRepresentationImpl(avpCode, vendorId);
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#getMessage(int, boolean)
*/
@Override
public MessageRepresentation getMessage(int commandCode, boolean isRequest) {
return this.getMessage(commandCode, 0, isRequest);
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#getMessage(int, long, boolean)
*/
@Override
public MessageRepresentation getMessage(int commandCode, long applicationId, boolean isRequest) {
if (!this.configured) {
return null;
}
MessageRepresentation key = new MessageRepresentationImpl(commandCode, applicationId, isRequest);
return this.commandMap.get(key);
}
// Validation ---------------------------------------------------------------
private boolean enabled = true;
private ValidatorLevel sendValidationLevel = ValidatorLevel.ALL;
private ValidatorLevel receiveValidationLevel = ValidatorLevel.OFF;
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#isValidate()
*/
@Override
public boolean isEnabled() {
return this.enabled;
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#getSendLevel()
*/
@Override
public ValidatorLevel getSendLevel() {
return this.sendValidationLevel;
}
/*
* (non-Javadoc)
*
* @see org.jdiameter.api.validation.Dictionary#getReceiveLevel()
*/
@Override
public ValidatorLevel getReceiveLevel() {
return this.receiveValidationLevel;
}
@Override
public void setSendLevel(ValidatorLevel level) {
this.sendValidationLevel = level;
}
@Override
public void setReceiveLevel(ValidatorLevel level) {
this.receiveValidationLevel = level;
}
@Override
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public void setConfigured(boolean configured) {
this.configured = configured;
}
@Override
public void validate(Message msg, boolean incoming) throws AvpNotAllowedException {
if (!enabled || !configured) {
return;
}
MessageRepresentationImpl rep = new MessageRepresentationImpl(msg.getCommandCode(), msg.getApplicationId(), msg.isRequest());
rep = (MessageRepresentationImpl) this.commandMap.get(rep);
if (rep == null) {
// no notion, lets leave it.
logger.warn("Validation could not be performed, command not defined!. Code={}, Application-Id={}, Req={}",
new Object[] { msg.getCommandCode(), msg.getApplicationId(), msg.isRequest() });
return;
}
rep.validate(msg, (incoming ? receiveValidationLevel : sendValidationLevel));
}
// Helper methods -----------------------------------------------------------
public Map<AvpRepresentation, AvpRepresentation> getAvpMap() {
return avpMap;
}
public Map<String, String> getVendorMap() {
return vendorMap;
}
public Map<MessageRepresentation, MessageRepresentation> getCommandMap() {
return commandMap;
}
public Map<String, String> getTypedefMap() {
return typedefMap;
}
public Map<String, AvpRepresentation> getNameToCodeMap() {
return avpByNameMap;
}
protected void printAvpTree(AvpRepresentation rep, String tab) {
String x = tab + "+-- " + rep.getCode() + "/" + rep.getVendorId();
while (x.length() < 25) {
x += ".";
}
System.out.println(x + rep.getName() + " > " + rep.getType());
if (rep.isGrouped()) {
for (AvpRepresentation repC : rep.getChildren()) {
printAvpTree(repC, " " + tab);
}
}
}
}