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(String 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 public Candidate(final TransportCandidate tc) { 319 super(tc); 320 } 321 322 /** 323 * Get the elements of this candidate. 324 */ 325 @Override 326 protected String getChildElements() { 327 StringBuilder buf = new StringBuilder(); 328 329 if (transportCandidate != null) { // && transportCandidate instanceof ICECandidate) { 330 ICECandidate tci = (ICECandidate) transportCandidate; 331 332 // We convert the transportElement candidate to XML here... 333 buf.append(" generation=\"").append(tci.getGeneration()).append('"'); 334 buf.append(" ip=\"").append(tci.getIp()).append('"'); 335 buf.append(" port=\"").append(tci.getPort()).append('"'); 336 buf.append(" network=\"").append(tci.getNetwork()).append('"'); 337 buf.append(" username=\"").append(tci.getUsername()).append('"'); 338 buf.append(" password=\"").append(tci.getPassword()).append('"'); 339 buf.append(" preference=\"").append(tci.getPreference()).append('"'); 340 buf.append(" type=\"").append(tci.getType()).append('"'); 341 342 // Optional elements 343 if (transportCandidate.getName() != null) { 344 buf.append(" name=\"").append(tci.getName()).append('"'); 345 } 346 } 347 348 return buf.toString(); 349 } 350 351 } 352 } 353 354 /** 355 * Raw UDP profile. 356 */ 357 public static class RawUdp extends JingleTransport { 358 public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0177.html#ns"; 359 360 public RawUdp() { 361 super(); 362 setNamespace(NAMESPACE); 363 } 364 365 /** 366 * Add a transport candidate. 367 * 368 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.jingleold.packet.JingleTransport.JingleTransportCandidate) 369 */ 370 @Override 371 public void addCandidate(final JingleTransportCandidate candidate) { 372 candidates.clear(); 373 super.addCandidate(candidate); 374 } 375 376 /** 377 * Get the list of candidates. As a "raw-udp" transport can only contain 378 * one candidate, we use the first in the list... 379 * 380 * @see org.jivesoftware.smackx.jingleold.packet.JingleTransport#getCandidates() 381 */ 382 @Override 383 public List<JingleTransportCandidate> getCandidatesList() { 384 List<JingleTransportCandidate> copy = new ArrayList<>(); 385 List<JingleTransportCandidate> superCandidatesList = super.getCandidatesList(); 386 if (superCandidatesList.size() > 0) { 387 copy.add(superCandidatesList.get(0)); 388 } 389 390 return copy; 391 } 392 393 /** 394 * Raw-udp transport candidate. 395 */ 396 public static class Candidate extends JingleTransportCandidate { 397 /** 398 * Default constructor. 399 */ 400 public Candidate() { 401 super(); 402 } 403 404 /** 405 * Constructor with a transport candidate. 406 */ 407 public Candidate(final TransportCandidate tc) { 408 super(tc); 409 } 410 411 /** 412 * Get the elements of this candidate. 413 */ 414 @Override 415 protected String getChildElements() { 416 StringBuilder buf = new StringBuilder(); 417 418 if (transportCandidate != null && transportCandidate instanceof TransportCandidate.Fixed) { 419 TransportCandidate.Fixed tcf = (TransportCandidate.Fixed) transportCandidate; 420 421 buf.append(" generation=\"").append(tcf.getGeneration()).append('"'); 422 buf.append(" ip=\"").append(tcf.getIp()).append('"'); 423 buf.append(" port=\"").append(tcf.getPort()).append('"'); 424 425 // Optional parameters 426 String name = tcf.getName(); 427 if (name != null) { 428 buf.append(" name=\"").append(name).append('"'); 429 } 430 } 431 return buf.toString(); 432 } 433 434 } 435 } 436}