blob: 3a528a932109a1c7f86b17870f4fbabf3eeed206 [file] [log] [blame]
/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), an agency of the Federal Government.
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain. As a result, a formal
* license is not needed to use the software.
*
* This software is provided by NIST as a service and is expressly
* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY. NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement
*
* .
*
*/
/*****************************************************************************
* PRODUCT OF PT INOVACAO - EST DEPARTMENT and Aveiro University - Portugal) *
*****************************************************************************/
package gov.nist.javax.sdp.fields;
import java.util.Vector;
import javax.sdp.SdpException;
import javax.sdp.SdpParseException;
import gov.nist.core.NameValue;
/**
* Precondition fields (segmented / end-to-end).
*
* <p>For one media description, precondition attributes should
* be only of one type (segmented or end-to-end) </p>
* <p>3GPP TS 24.299, </p>
* IETF RFC3312 + RFC4032 (Precondition Mechanism).
*
* @author Miguel Freitas (IT) PT-Inovacao
*/
public class PreconditionFields
{
// Media Description attributes for precondition
protected Vector preconditionAttributes;
/**
* Constructor
*
*/
public PreconditionFields()
{
preconditionAttributes = new Vector();
}
/**
* Get the number of Precondition attributes
*
* @return int size of segmented precondition vector of attribute fields
*/
public int getPreconditionSize()
{
if (preconditionAttributes != null)
return preconditionAttributes.size();
else // TODO treat this exception well
return -1;
}
/**
* Get Precondition
*
* @return Vector of attribute fields (segmented precondition)
*/
public Vector getPreconditions()
{
return preconditionAttributes;
}
/**
* Set Preconditions
*
* @param preconditions - vector with precondition attributes
* @throws SdpException -- if precondition attributes is null
*/
public void setPreconditions(Vector preconditions) throws SdpException
{
if (preconditions == null)
throw new SdpException("Precondition attributes are null");
else
preconditionAttributes = preconditions;
}
/**
* <p>Set attribute line for current precondition state, given
* a string value encoded like the "curr" attribute value</p>
*
* @param precondCurrValue - a string with the value for a "curr" attribute
* @throws SdpException
*/
public void setPreconditionCurr(String precondCurrValue) throws SdpException
{
if (precondCurrValue == null)
throw new SdpException("The Precondition \"curr\" attribute value is null");
else if (preconditionAttributes == null)
throw new SdpException("The Precondition Attributes is null");
else
{
try
{
/* split the "curr" attribute value into words
* attributes[0] = "qos"
* attributes[1] = status-type (e2e/local/remote)
* attributes[2] = direction-tag (none/send/recv/sendrecv)
*
* split() - regular expression:
* \s -> a whitespace character [ \t\n\x0B\f\r]
* \b -> a word boundary
*/
String[] attributes = precondCurrValue.split(" ");
// which is this length?! of the string or the []?
/*
if (attributes.length < 3)
{
throw new SdpException
("The Precondition \"curr\" attribute value mal-formed (<3words)");
}*/
setPreconditionCurr(attributes[1], // status-type
attributes[2] // direction-tag
);
}
catch (ArrayIndexOutOfBoundsException ex)
{
throw new SdpException
("Error spliting the \"curr\" attribute into words", ex);
}
}
}
/**
* <p>Set the value of the attributes with the name "curr"
* for current precondition.</p>
* <p>- eg: a=curr:qos local none</p>
*
* <p>If there is an attribute "curr" for the same status-type,
* the direction-tag is updated with the one supplied.</p>
*
* @param status - (local, remote, e2e)
* @param directionTag - (none, send, recv, sendrecv)
* @throws SdpParseException
*/
public void setPreconditionCurr(String status, String directionTag)
throws SdpException
{
if (status == null)
throw new SdpException("The status-type is null");
if (directionTag == null)
throw new SdpException("The direction-tag is null");
if (preconditionAttributes == null)
throw new SdpException("Precondition Attributes is null");
int i = 0;
// search for attributes "curr"
for (i = 0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
// go to next attribute if this is not "curr"
if (!af.getAttribute().getName().equals("curr"))
continue;
// if it is "curr" attribute, check the status-type
// if it matches the value supplied, update the direction-tag
// with the value supplied
if (af.getValue().indexOf(status) != -1)
{
if (af.getValue().indexOf(directionTag) == -1)
{
// attribute exists with same status, directionTag updated
af.setValue("qos " + status + " " + directionTag);
preconditionAttributes.setElementAt(af,i);
}
// else, exit and do nothing (attribute already exists)
else
break;
}
}
// attribute "curr" not found
if (i == preconditionAttributes.size())
{
// create attribute for the status-type supplied
NameValue nv = new NameValue("curr", "qos " + status + " " + directionTag);
AttributeField newAF = new AttributeField();
newAF.setAttribute(nv);
preconditionAttributes.add(newAF);
}
}
/**
* <p>Set attribute line for desired precondition state, given
* a string value encoded like the "des" attribute value</p>
*
* @param precondDesValue - a string with the value for a "des" attribute
* @throws SdpException
*/
public void setPreconditionDes(String precondDesValue) throws SdpException
{
if (precondDesValue == null)
throw new SdpException("The Precondition \"des\" attribute value is null");
else if (preconditionAttributes == null)
throw new SdpException("The Precondition Attributes is null");
else
{
/* split the "des" attribute value into words
* attributes[0] = "qos"
* attributes[1] = strength-tag (unknown/failure/none/optional/mandatory)
* attributes[2] = status-type (e2e/local/remote)
* attributes[3] = direction-tag (none/send/recv/sendrecv)
*
* split() - regular expression:
* \s -> a whitespace character [ \t\n\x0B\f\r]
* \b -> a word boundary
*/
try
{
String[] attributes = precondDesValue.split(" ");
// which is this length?! of the string or the []?
/*
if (attributes.length < 4)
{
throw new SdpException
("The Precondition \"des\" attribute value mal-formed (<4words)");
}*/
setPreconditionDes( attributes[1], // strength-tag
attributes[2], // status-type
attributes[3] // direction-tag
);
}
catch (ArrayIndexOutOfBoundsException ex)
{
throw new SdpException
("Error spliting the \"des\" attribute into words", ex);
}
}
}
/**
* <p>Set the value of the attributes with the name "des"
* for desired precondition. </p>
* <p>- eg: a=des:qos mandatory remote sendrecv</p>
*
* <p>There can be more than one desired precondition line
* for a status-type, specially if strength-tag is different.</p>
*
* <p>If there is an attribute "des" for the same status-type,
* the strength-tag and direction-tag are updated with the
* ones supplied.<p>
*
* <p>IETF RFC4032: strength should only be downgraded within SDP offers</p>
*
*
* @param strength - (none, optional,
* @param status - (local, remote, e2e)
* @param direction - (none, send, recv, sendrecv)
* @throws SdpParseException
*/
public void setPreconditionDes(String strength, String status, String direction)
throws SdpException
{
if (strength == null)
throw new SdpException("The strength-tag is null");
if (status == null)
throw new SdpException("The status-type is null");
if (direction == null)
throw new SdpException("The direction-tag is null");
if (preconditionAttributes == null)
throw new SdpException("Precondition Attributes is null");
int i = 0;
// search for attributes "des"
for (i = 0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
// go to next attribute if this is not "des"
if (!af.getAttribute().getName().equals("des"))
continue;
// if it is "des" attribute, check the status-type
// if it match, update the strength-tag and direction-tag
if (af.getValue().indexOf(status) != -1)
{
// attribute exists with same status-type,
// strength-tag and direction-tag updated
af.setValue("qos " + strength + " " + status + " " + direction);
preconditionAttributes.setElementAt(af,i);
}
}
// attribute "des" not found
if (i == preconditionAttributes.size())
{
// create attribute for the status-type supplied
// with the values strength-tag and direction-tag
NameValue nv =
new NameValue("des", "qos " + strength + " " + status + " " + direction);
AttributeField newAF = new AttributeField();
newAF.setAttribute(nv);
preconditionAttributes.add(newAF);
}
}
/**
* <p>Set attribute line for confirmation precondition request, given
* a string value encoded like the "conf" attribute value</p>
*
* @param precondConfValue - a string with the value for a "conf" attribute
* @throws SdpException
*/
public void setPreconditionConfirmStatus(String precondConfValue)
throws SdpException
{
if (precondConfValue == null || precondConfValue.length()==0)
throw new SdpException("The Precondition \"conf\" attribute value is null");
else if (preconditionAttributes == null)
throw new SdpException("The Precondition Attributes is null");
else
{
/* split the "conf" attribute value into words
* attributes[0] = "qos"
* attributes[1] = status-type (e2e/local/remote)
* attributes[2] = direction-tag (none/send/recv/sendrecv)
*/
try
{
String[] attributes = precondConfValue.split(" ");
setPreconditionConfirmStatus(
attributes[1], // status-type
attributes[2] // direction-tag
);
}
catch (ArrayIndexOutOfBoundsException ex)
{
throw new SdpException
("Error spliting the \"conf\" attribute into words", ex);
}
}
}
/**
* <p>IETF RFC3312</p>
* <p>"The confirmation status attribute carries threshold conditions
* for a media stream. When the status of network resources reach
* these conditions, the peer UA will send an update of the
* session description".</p>
*
* <p>- eg: a=conf:qos remote sendrecv</p>
*
* @param status - (e2e, local, remote)
* @param direction - (none, send, recv, sendrecv)
* @throws SdpException -- if param are null
*/
public void setPreconditionConfirmStatus(String status, String direction)
throws SdpException
{
if (status == null || direction.length()==0)
throw new SdpException("The status-type is null");
if (direction == null || direction.length()==0)
throw new SdpException("The direction-tag is null");
if (preconditionAttributes == null)
throw new SdpException("Precondition Attributes is null");
int i = 0;
// search for attributes "conf"
for (i = 0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
//System.out.println("--> PreconditionField -> (i="+i+") > attribute field: " + af.toString());
// go to next attribute if this is not "conf"
if (!af.getAttribute().getName().equals("conf"))
continue;
// if it is "conf" attribute, check the status-type
// if it matches, update the direction-tag
// with the value supplied
if (af.getValue().indexOf(status) != -1)
{
if (af.getValue().indexOf(direction) == -1)
{
// attribute exists with same status, directionTag updated
af.setValue("qos " + status + " " + direction);
preconditionAttributes.setElementAt(af,i);
}
// else, exit and do nothing (attribute already exists)
break;
}
}
// attribute "conf" not found
if (i == preconditionAttributes.size())
{
// create attribute for the status-type supplied
// with the values strength-tag and direction-tag
NameValue nv =
new NameValue("conf", "qos " + status + " " + direction);
AttributeField newAF = new AttributeField();
newAF.setAttribute(nv);
preconditionAttributes.add(newAF);
//System.out.println("--> PreconditionField -> new \"conf\" attribute created: " + newAF.toString() );
}
}
/**
* <p>Get the attribute fields with the name "curr"
* for current precondition.</p>
* <p>One attribute field per status-type.
* (eg: a=curr:qos local none)</p>
*
* @param status - (local, remote, e2e)
* @return a vector with the attribute field that match status-type
* (with only one element or null if none exists)
* @throws SdpParseException
*/
public Vector getPreconditionCurr(String status)
throws SdpException, SdpParseException
{
if (status == null)
throw new SdpException("The status-type is null");
if (preconditionAttributes == null)
return null;
else
{
Vector vCurr = new Vector();
for (int i=0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
// go to next attribute if this is not "curr"
if (!af.getAttribute().getName().equals("curr"))
continue;
// if it is "curr" attribute, check the status-type
// and add the attribute value to the vector if it
// matches the status desired
if (af.getValue().indexOf(status) != -1)
vCurr.addElement(af);
}
// if none "curr" attribute found
if (vCurr.size() == 0)
return null;
else
return vCurr;
}
}
/**
* <p>Get the attribute fields with the name "des"
* for desired precondition</p>
*
* <p>There can be more than one current precondition line
* for a status-type (with different direction-tag values),
* specially if strength-tag is different</p>
*
* @param status - (local, remote, e2e)
* @return a vector with the attribute fields that match location-tag
* @throws SdpParseException
*/
public Vector getPreconditionDes(String status)
throws SdpException, SdpParseException
{
if (status == null)
throw new SdpException("The status-type is null");
if (preconditionAttributes == null)
return null;
else
{
Vector vCurr = new Vector();
for (int i=0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
// go to next attribute if this is not "des"
if (!af.getAttribute().getName().equals("des"))
continue;
// if it is "des" attribute, check the status-type
// and add the attribute value to the vector if it
// matches the status desired
if (af.getValue().indexOf(status) != -1)
vCurr.addElement(af);
}
// if none "des" attribute found
if (vCurr.size() == 0)
return null;
else
return vCurr;
}
}
/**
* <p>Get the attribute fields with the name "conf"
* for confirmation precondition.</p>
*
* <p>IETF RFC3312</p>
* <p>"The confirmation status attribute carries threshold conditions
* for a media stream. When the status of network resources reach
* these conditions, the peer UA will send an update of the
* session description".</p>
*
* <p>(eg: a=conf:qos remote sendrecv)</p>
*
* @return a vector with the "conf" attribute fields
* @throws SdpException
*/
public Vector getPreconditionConfirmStatus() throws SdpException
{
if (preconditionAttributes == null)
return null; // ignore or send SdpException?
else
{
Vector vCurr = new Vector();
for (int i=0; i < preconditionAttributes.size(); i++)
{
AttributeField af =
(AttributeField) this.preconditionAttributes.elementAt(i);
// go to next attribute if this is not "conf"
if (!af.getAttribute().getName().equals("conf"))
continue;
else
// add the attribute value to the vector
vCurr.addElement(af);
}
// if none "conf" attribute found
if (vCurr.size() == 0)
return null;
else
return vCurr;
}
}
/* strength-tag */
public static final int STRENGTH_UNKNOWN = 0;
public static final int STRENGTH_FAILURE = 1;
public static final int STRENGTH_NONE = 2;
public static final int STRENGTH_OPTIONAL = 3;
public static final int STRENGTH_MANDATORY = 4;
public static final String[] STRENGTH = { "unknown",
"failure",
"none",
"optional",
"mandatory"
};
/* direction-tag */
public static final int DIRECTION_NONE = 0;
public static final int DIRECTION_SEND = 1;
public static final int DIRECTION_RECV = 2;
public static final int DIRECTION_SENDRECV = 3;
public static final String[] DIRECTION = { "none",
"send",
"recv",
"sendrecv"
};
/* status-tag */
public static final int STATUS_E2E = 0;
public static final int STATUS_LOCAL = 1;
public static final int STATUS_REMOTE = 2;
public static final String[] STATUS = { "e2e",
"local",
"remote"
};
/* precondition type */
public static final int PRECONDITION_QOS = 0;
public static final String[] PRECONDITION = { "qos"
};
}