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