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