1 /*
2 * jSDP: A Java implementation of SDP protocol Copyright (C) 2007 Claudio Di
3 * Vita
4 */
5 package net.sourceforge.jsdp;
6
7 import java.util.regex.Matcher;
8 import java.util.regex.Pattern;
9
10 /**
11 * An <tt>Attribute</tt> represents an <b>a=<i><field value></i></b>
12 * field contained in a SDP message. Attribute fields may be of two forms:
13 * <ul>
14 * <li>Property attribute, that is simply of the form <i><b>a=<flag></i></b>.
15 * These are binary attributes, and the presence of the attribute conveys that
16 * the attribute is a property of the session. An example might be <i>a=recvonly</i></li>
17 * <li>Value attribute, that is of the form <b>a=<i><attribute>:<value></i></b>.
18 * For example, a whiteboard could have the value attribute
19 * <i>a=orient:landscape</i></li>
20 * </ul>
21 * <p>
22 * Obviously attribute field interpretation depends on the media tool being
23 * invoked.
24 * </p>
25 *
26 * @since 0.1.0
27 *
28 * @version 1.1
29 *
30 * @author <a href="mailto:cdivita@users.sourceforge.net">Claudio Di Vita</a>
31 */
32 public class Attribute implements Field {
33
34 /** The class Stream Unique Identifier, SUID */
35 private static final long serialVersionUID = -6003475409338057035L;
36
37 /** The pattern used to parse the field */
38 private static final Pattern fieldPattern = Pattern.compile("([^:]+)(:((.+)))?");
39
40 /** The pattern used to validate the attribute name */
41 private static final Pattern namePattern = Pattern.compile("(\\w)+(-\\w+)*");
42
43 /** The pattern used to validate the attribute value */
44 private static final Pattern valuePattern = Pattern.compile("[^\0\\r\\n]+");
45
46 /** The attribute property name */
47 protected String name;
48
49 /** The attribute value */
50 protected String value;
51
52 /**
53 * Creates a new <tt>Attribute</tt>.
54 */
55 protected Attribute() {
56
57 super();
58 }
59
60 /**
61 * Creates a new <tt>Attribute</tt>.
62 *
63 * @param name the attribute name
64 *
65 * @throws SDPException if the name is <tt>null</tt> or not valid
66 */
67 public Attribute(final String name) throws SDPException {
68
69 super();
70
71 setName(name);
72 this.value = null;
73 }
74
75 /**
76 * Creates a new <tt>Attribute</tt>.
77 *
78 * @param name the attribute name
79 *
80 * @param value the attribute value
81 *
82 * @throws SDPException if the name is <tt>null</tt> or not valid, or the
83 * value is not valid
84 */
85 public Attribute(final String name, final String value) throws SDPException {
86
87 super();
88
89 setName(name);
90 setValue(value);
91 }
92
93 /**
94 * Parse an input string and constructs the equivalent attribute field.
95 *
96 * @param field the string to parse
97 *
98 * @return a new <tt>Attribute</tt> instance
99 *
100 * @throws SDPParseException if an error occurs while parsing
101 */
102 public static Attribute parse(final String field) throws SDPParseException {
103
104 if (!field.startsWith("a=")) {
105 throw new SDPParseException("The string \"" + field + "\" isn't an attribute field");
106 }
107
108 Attribute a = null;
109 Matcher matcher = fieldPattern.matcher(field.substring(2));
110
111 /* Test */
112 if (matcher.matches()) {
113
114 try {
115 /* The attribute has the form a=<attribute>:<value> */
116 if (matcher.group(3) != null) {
117 a = new Attribute(matcher.group(1), matcher.group(3));
118 }
119 else {
120 /* The attribute has the form a=<flag> */
121 a = new Attribute(matcher.group(1));
122 }
123 }
124 catch (SDPException parseException) {
125 throw new SDPParseException("The string \"" + field + "\" isn't a valid attribute field", parseException);
126 }
127 }
128 else {
129 throw new SDPParseException("The string \"" + field + "\" isn't a valid attribute field");
130 }
131
132 return a;
133 }
134
135 /*
136 * (non-Javadoc)
137 *
138 * @see net.sourceforge.jsdp.Field#clone()
139 */
140 public Object clone() {
141
142 Attribute field = new Attribute();
143 field.name = new String(this.name);
144
145 if (this.value != null) {
146 field.value = new String(this.value);
147 }
148 else {
149 field.value = null;
150 }
151
152 return field;
153 }
154
155 /**
156 * Returns the name of the attribute.
157 *
158 * @return the attribute name
159 */
160 public String getName() {
161
162 return name;
163 }
164
165 /**
166 * Returns the type character for the field.
167 *
168 * @return the field type character: <b>a</b>
169 */
170 public char getType() {
171
172 return Field.ATTRIBUTE_FIELD;
173 }
174
175 /**
176 * Returns the value of the attribute.
177 *
178 * @return a <tt>String</tt> if the attribute has an associated value
179 * <tt>null</tt> otherwise
180 */
181 public String getValue() {
182
183 return value;
184 }
185
186 /**
187 * Determines if this attribute has an associated value.
188 *
189 * @return <tt>true</tt> if the attribute has a value, <tt>false</tt>
190 * otherwise
191 */
192 public boolean hasValue() {
193
194 return value != null;
195 }
196
197 /**
198 * Resets the attribute value.
199 */
200 public void resetValue() {
201
202 this.value = null;
203 }
204
205 /**
206 * Sets the name of the attribute.
207 *
208 * @param name the name/id of the attribute
209 *
210 * @throws SDPException if the name is <tt>null</tt> or not valid
211 */
212 public void setName(final String name) throws SDPException {
213
214 if (name == null) {
215 throw new SDPException("The attribute name cannot be null");
216 }
217
218 if (!namePattern.matcher(name).matches()) {
219 throw new SDPException("Invalid attribute name: " + name);
220 }
221
222 this.name = name;
223 }
224
225 /**
226 * Sets the value of this attribute.
227 *
228 * @param value the attribute value
229 *
230 * @throws SDPException if the specified value is not valid
231 */
232 public void setValue(final String value) throws SDPException {
233
234 if (value != null && !valuePattern.matcher(value).matches()) {
235 throw new SDPException("Invalid attribute value: " + value);
236 }
237
238 this.value = value;
239 }
240
241 /**
242 * Returns a string representation of the field. The representation can had
243 * the following forms:
244 * <ul>
245 * <li><b>a=<i><flag></i></b></li>
246 * <li><b>a=<i><attribute></i>:<i><value></i></b></li>
247 * </ul>
248 *
249 * @return the string representation of the field
250 */
251 public String toString() {
252
253 StringBuffer result;
254
255 result = new StringBuffer(getType() + "=");
256 result.append(name);
257
258 if (hasValue()) {
259 result.append(":" + value);
260 }
261
262 return result.toString();
263 }
264 }