View Javadoc

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>&lt;field value&gt;</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=&lt;flag&gt;</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>&lt;attribute&gt;:&lt;value&gt;</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>&lt;flag&gt;</i></b></li>
246      * <li><b>a=<i>&lt;attribute&gt;</i>:<i>&lt;value&gt;</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 }