001/** 002 * 003 * Copyright 2003-2005 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.jingleold.packet; 018 019import java.util.ArrayList; 020import java.util.Collections; 021import java.util.Iterator; 022import java.util.List; 023 024import org.jivesoftware.smack.packet.ExtensionElement; 025 026import org.jivesoftware.smackx.jingleold.nat.ICECandidate; 027import org.jivesoftware.smackx.jingleold.nat.TransportCandidate; 028 029/** 030 * A jingle transport extension. 031 * 032 * @author Alvaro Saurin 033 */ 034public class JingleTransport implements ExtensionElement { 035 036 // static 037 038 public static final String NODENAME = "transport"; 039 040 // non-static 041 042 protected String namespace; 043 044 protected final List<JingleTransportCandidate> candidates = new ArrayList<JingleTransportCandidate>(); 045 046 /** 047 * Default constructor. 048 */ 049 public JingleTransport() { 050 super(); 051 } 052 053 /** 054 * Utility constructor, with a transport candidate element. 055 * 056 * @param candidate A transport candidate element to add. 057 */ 058 @SuppressWarnings("this-escape") 059 public JingleTransport(final JingleTransportCandidate candidate) { 060 super(); 061 addCandidate(candidate); 062 } 063 064 /** 065 * Copy constructor. 066 * 067 * @param tr the other jingle transport. 068 */ 069 public JingleTransport(final JingleTransport tr) { 070 if (tr != null) { 071 namespace = tr.namespace; 072 073 if (tr.candidates.size() > 0) { 074 candidates.addAll(tr.candidates); 075 } 076 } 077 } 078 079 /** 080 * Adds a transport candidate. 081 * 082 * @param candidate the candidate 083 */ 084 public void addCandidate(final JingleTransportCandidate candidate) { 085 if (candidate != null) { 086 synchronized (candidates) { 087 candidates.add(candidate); 088 } 089 } 090 } 091 092 /** 093 * Get an iterator for the candidates. 094 * 095 * @return an iterator 096 */ 097 public Iterator<JingleTransportCandidate> getCandidates() { 098 return Collections.unmodifiableList(getCandidatesList()).iterator(); 099 } 100 101 /** 102 * Get the list of candidates. 103 * 104 * @return The candidates list. 105 */ 106 public List<JingleTransportCandidate> getCandidatesList() { 107 ArrayList<JingleTransportCandidate> res; 108 synchronized (candidates) { 109 res = new ArrayList<>(candidates); 110 } 111 return res; 112 } 113 114 /** 115 * Get the number of transport candidates. 116 * 117 * @return The number of transport candidates contained. 118 */ 119 public int getCandidatesCount() { 120 return getCandidatesList().size(); 121 } 122 123 /** 124 * Returns the XML element name of the element. 125 * 126 * @return the XML element name of the element. 127 */ 128 @Override 129 public String getElementName() { 130 return NODENAME; 131 } 132 133 /** 134 * Set the namespace. 135 * 136 * @param ns The namespace 137 */ 138 protected void setNamespace(final String ns) { 139 namespace = ns; 140 } 141 142 /** 143 * Get the namespace. 144 * 145 * @return The namespace 146 */ 147 @Override 148 public String getNamespace() { 149 return namespace; 150 } 151 152 /** 153 * Return the XML representation for this element. 154 */ 155 @Override 156 public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 157 StringBuilder buf = new StringBuilder(); 158 159 buf.append('<').append(getElementName()).append(" xmlns=\""); 160 buf.append(getNamespace()).append("\" "); 161 162 synchronized (candidates) { 163 if (getCandidatesCount() > 0) { 164 buf.append('>'); 165 Iterator<JingleTransportCandidate> iter = getCandidates(); 166 167 while (iter.hasNext()) { 168 JingleTransportCandidate candidate = iter.next(); 169 buf.append(candidate.toXML()); 170 } 171 buf.append("</").append(getElementName()).append('>'); 172 } else { 173 buf.append("/>"); 174 } 175 } 176 177 return buf.toString(); 178 } 179 180 /** 181 * Candidate element in the transport. This class acts as a view of the 182 * "TransportCandidate" in the Jingle space. 183 * 184 * @author Alvaro Saurin 185 * @see TransportCandidate 186 */ 187 public abstract static class JingleTransportCandidate { 188 189 public static final String NODENAME = "candidate"; 190 191 // The transport candidate contained in the element. 192 protected TransportCandidate transportCandidate; 193 194 /** 195 * Creates a new TransportNegotiator child. 196 */ 197 public JingleTransportCandidate() { 198 super(); 199 } 200 201 /** 202 * Creates a new TransportNegotiator child. 203 * 204 * @param candidate the jmf transport candidate 205 */ 206 @SuppressWarnings("this-escape") 207 public JingleTransportCandidate(final TransportCandidate candidate) { 208 super(); 209 setMediaTransport(candidate); 210 } 211 212 /** 213 * Returns the XML element name of the element. 214 * 215 * @return the XML element name of the element. 216 */ 217 public static String getElementName() { 218 return NODENAME; 219 } 220 221 /** 222 * Get the current transportElement candidate. 223 * 224 * @return the transportElement candidate 225 */ 226 public TransportCandidate getMediaTransport() { 227 return transportCandidate; 228 } 229 230 /** 231 * Set the transportElement candidate. 232 * 233 * @param cand the transportElement candidate 234 */ 235 public void setMediaTransport(final TransportCandidate cand) { 236 if (cand != null) { 237 transportCandidate = cand; 238 } 239 } 240 241 /** 242 * Get the list of attributes. 243 * 244 * @return a string with the list of attributes. 245 */ 246 protected String getChildElements() { 247 return null; 248 } 249 250 /** 251 * Obtain a valid XML representation of a transport candidate. 252 * 253 * @return A string containing the XML dump of the transport candidate. 254 */ 255 public String toXML() { 256 StringBuilder buf = new StringBuilder(); 257 String childElements = getChildElements(); 258 259 if (transportCandidate != null && childElements != null) { 260 buf.append('<').append(getElementName()).append(' '); 261 buf.append(childElements); 262 buf.append("/>"); 263 } 264 265 return buf.toString(); 266 } 267 } 268 269 // Subclasses 270 271 /** 272 * RTP-ICE profile. 273 */ 274 public static class Ice extends JingleTransport { 275 public static final String NAMESPACE = "urn:xmpp:tmp:jingle:transports:ice-udp"; 276 277 @SuppressWarnings("this-escape") 278 public Ice() { 279 super(); 280 setNamespace(NAMESPACE); 281 } 282 283 /** 284 * Add a transport candidate. 285 * 286 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.jingleold.packet.JingleTransport.JingleTransportCandidate) 287 */ 288 @Override 289 public void addCandidate(final JingleTransportCandidate candidate) { 290 super.addCandidate(candidate); 291 } 292 293 /** 294 * Get the list of candidates. As a "raw-udp" transport can only contain 295 * one candidate, we use the first in the list... 296 * 297 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#getCandidates() 298 */ 299 @Override 300 public List<JingleTransportCandidate> getCandidatesList() { 301 List<JingleTransportCandidate> copy = new ArrayList<>(); 302 List<JingleTransportCandidate> superCandidatesList = super.getCandidatesList(); 303 for (int i = 0; i < superCandidatesList.size(); i++) { 304 copy.add(superCandidatesList.get(i)); 305 } 306 307 return copy; 308 } 309 310 public static class Candidate extends JingleTransportCandidate { 311 /** 312 * Default constructor. 313 */ 314 public Candidate() { 315 super(); 316 } 317 318 /** 319 * Constructor with a transport candidate. 320 * 321 * @param tc the transport candidate. 322 */ 323 public Candidate(final TransportCandidate tc) { 324 super(tc); 325 } 326 327 /** 328 * Get the elements of this candidate. 329 */ 330 @Override 331 protected String getChildElements() { 332 StringBuilder buf = new StringBuilder(); 333 334 if (transportCandidate != null) { // && transportCandidate instanceof ICECandidate) { 335 ICECandidate tci = (ICECandidate) transportCandidate; 336 337 // We convert the transportElement candidate to XML here... 338 buf.append(" generation=\"").append(tci.getGeneration()).append('"'); 339 buf.append(" ip=\"").append(tci.getIp()).append('"'); 340 buf.append(" port=\"").append(tci.getPort()).append('"'); 341 buf.append(" network=\"").append(tci.getNetwork()).append('"'); 342 buf.append(" username=\"").append(tci.getUsername()).append('"'); 343 buf.append(" password=\"").append(tci.getPassword()).append('"'); 344 buf.append(" preference=\"").append(tci.getPreference()).append('"'); 345 buf.append(" type=\"").append(tci.getType()).append('"'); 346 347 // Optional elements 348 if (transportCandidate.getName() != null) { 349 buf.append(" name=\"").append(tci.getName()).append('"'); 350 } 351 } 352 353 return buf.toString(); 354 } 355 356 } 357 } 358 359 /** 360 * Raw UDP profile. 361 */ 362 public static class RawUdp extends JingleTransport { 363 public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0177.html#ns"; 364 365 @SuppressWarnings("this-escape") 366 public RawUdp() { 367 super(); 368 setNamespace(NAMESPACE); 369 } 370 371 /** 372 * Add a transport candidate. 373 * 374 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.jingleold.packet.JingleTransport.JingleTransportCandidate) 375 */ 376 @Override 377 public void addCandidate(final JingleTransportCandidate candidate) { 378 candidates.clear(); 379 super.addCandidate(candidate); 380 } 381 382 /** 383 * Get the list of candidates. As a "raw-udp" transport can only contain 384 * one candidate, we use the first in the list... 385 * 386 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#getCandidates() 387 */ 388 @Override 389 public List<JingleTransportCandidate> getCandidatesList() { 390 List<JingleTransportCandidate> copy = new ArrayList<>(); 391 List<JingleTransportCandidate> superCandidatesList = super.getCandidatesList(); 392 if (superCandidatesList.size() > 0) { 393 copy.add(superCandidatesList.get(0)); 394 } 395 396 return copy; 397 } 398 399 /** 400 * Raw-udp transport candidate. 401 */ 402 public static class Candidate extends JingleTransportCandidate { 403 /** 404 * Default constructor. 405 */ 406 public Candidate() { 407 super(); 408 } 409 410 /** 411 * Constructor with a transport candidate. 412 * 413 * @param tc the transport candidate. 414 */ 415 public Candidate(final TransportCandidate tc) { 416 super(tc); 417 } 418 419 /** 420 * Get the elements of this candidate. 421 */ 422 @Override 423 protected String getChildElements() { 424 StringBuilder buf = new StringBuilder(); 425 426 if (transportCandidate != null && transportCandidate instanceof TransportCandidate.Fixed) { 427 TransportCandidate.Fixed tcf = (TransportCandidate.Fixed) transportCandidate; 428 429 buf.append(" generation=\"").append(tcf.getGeneration()).append('"'); 430 buf.append(" ip=\"").append(tcf.getIp()).append('"'); 431 buf.append(" port=\"").append(tcf.getPort()).append('"'); 432 433 // Optional parameters 434 String name = tcf.getName(); 435 if (name != null) { 436 buf.append(" name=\"").append(name).append('"'); 437 } 438 } 439 return buf.toString(); 440 } 441 442 } 443 } 444}