/**
* $RCSfile: JingleTransport.java,v $
* $Revision: 1.1 $
* $Date: 2007/07/02 17:41:08 $
*
* Copyright 2003-2005 Jive Software.
*
* All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smackx.packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smackx.jingle.nat.ICECandidate;
import org.jivesoftware.smackx.jingle.nat.TransportCandidate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* A jingle transport extension
*
* @author Alvaro Saurin <alvaro.saurin@gmail.com>
*/
public class JingleTransport implements PacketExtension {
// static
public static final String NODENAME = "transport";
// non-static
protected String namespace;
protected final List<JingleTransportCandidate> candidates = new ArrayList<JingleTransportCandidate>();
/**
* Default constructor.
*/
public JingleTransport() {
super();
}
/**
* Utility constructor, with a transport candidate element.
*
* @param candidate A transport candidate element to add.
*/
public JingleTransport(final JingleTransportCandidate candidate) {
super();
addCandidate(candidate);
}
/**
* Copy constructor.
*
* @param tr the other jingle transport.
*/
public JingleTransport(final JingleTransport tr) {
if (tr != null) {
namespace = tr.namespace;
if (tr.candidates.size() > 0) {
candidates.addAll(tr.candidates);
}
}
}
/**
* Adds a transport candidate.
*
* @param candidate the candidate
*/
public void addCandidate(final JingleTransportCandidate candidate) {
if (candidate != null) {
synchronized (candidates) {
candidates.add(candidate);
}
}
}
/**
* Get an iterator for the candidates
*
* @return an iterator
*/
public Iterator<JingleTransportCandidate> getCandidates() {
return Collections.unmodifiableList(getCandidatesList()).iterator();
}
/**
* Get the list of candidates.
*
* @return The candidates list.
*/
public List<JingleTransportCandidate> getCandidatesList() {
ArrayList<JingleTransportCandidate> res = null;
synchronized (candidates) {
res = new ArrayList<JingleTransportCandidate>(candidates);
}
return res;
}
/**
* Get the number of transport candidates.
*
* @return The number of transport candidates contained.
*/
public int getCandidatesCount() {
return getCandidatesList().size();
}
/**
* Returns the XML element name of the element.
*
* @return the XML element name of the element.
*/
public String getElementName() {
return NODENAME;
}
/**
* Set the namespace.
*
* @param ns The namespace
*/
protected void setNamespace(final String ns) {
namespace = ns;
}
/**
* Get the namespace.
*
* @return The namespace
*/
public String getNamespace() {
return namespace;
}
/**
* Return the XML representation for this element.
*/
public String toXML() {
StringBuilder buf = new StringBuilder();
buf.append("<").append(getElementName()).append(" xmlns=\"");
buf.append(getNamespace()).append("\" ");
synchronized (candidates) {
if (getCandidatesCount() > 0) {
buf.append(">");
Iterator<JingleTransportCandidate> iter = getCandidates();
while (iter.hasNext()) {
JingleTransportCandidate candidate = iter.next();
buf.append(candidate.toXML());
}
buf.append("</").append(getElementName()).append(">");
} else {
buf.append("/>");
}
}
return buf.toString();
}
/**
* Candidate element in the transport. This class acts as a view of the
* "TransportCandidate" in the Jingle space.
*
* @author Alvaro Saurin
* @see TransportCandidate
*/
public static abstract class JingleTransportCandidate {
public static final String NODENAME = "candidate";
// The transport candidate contained in the element.
protected TransportCandidate transportCandidate;
/**
* Creates a new TransportNegotiator child.
*/
public JingleTransportCandidate() {
super();
}
/**
* Creates a new TransportNegotiator child.
*
* @param candidate the jmf transport candidate
*/
public JingleTransportCandidate(final TransportCandidate candidate) {
super();
setMediaTransport(candidate);
}
/**
* Returns the XML element name of the element.
*
* @return the XML element name of the element.
*/
public static String getElementName() {
return NODENAME;
}
/**
* Get the current transportElement candidate.
*
* @return the transportElement candidate
*/
public TransportCandidate getMediaTransport() {
return transportCandidate;
}
/**
* Set the transportElement candidate.
*
* @param cand the transportElement candidate
*/
public void setMediaTransport(final TransportCandidate cand) {
if (cand != null) {
transportCandidate = cand;
}
}
/**
* Get the list of attributes.
*
* @return a string with the list of attributes.
*/
protected String getChildElements() {
return null;
}
/**
* Obtain a valid XML representation of a trancport candidate
*
* @return A string containing the XML dump of the transport candidate.
*/
public String toXML() {
StringBuilder buf = new StringBuilder();
String childElements = getChildElements();
if (transportCandidate != null && childElements != null) {
buf.append("<").append(getElementName()).append(" ");
buf.append(childElements);
buf.append("/>");
}
return buf.toString();
}
}
// Subclasses
/**
* RTP-ICE profile
*/
public static class Ice extends JingleTransport {
public static final String NAMESPACE = "urn:xmpp:tmp:jingle:transports:ice-udp";
public Ice() {
super();
setNamespace(NAMESPACE);
}
/**
* Add a transport candidate
*
* @see org.jivesoftware.smackx.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.packet.JingleTransport.JingleTransportCandidate)
*/
public void addCandidate(final JingleTransportCandidate candidate) {
super.addCandidate(candidate);
}
/**
* Get the list of candidates. As a "raw-udp" transport can only contain
* one candidate, we use the first in the list...
*
* @see org.jivesoftware.smackx.packet.JingleTransport#getCandidates()
*/
public List<JingleTransportCandidate> getCandidatesList() {
List<JingleTransportCandidate> copy = new ArrayList<JingleTransportCandidate>();
List<JingleTransportCandidate> superCandidatesList = super.getCandidatesList();
for (int i = 0; i < superCandidatesList.size(); i++) {
copy.add(superCandidatesList.get(i));
}
return copy;
}
public static class Candidate extends JingleTransportCandidate {
/**
* Default constructor
*/
public Candidate() {
super();
}
/**
* Constructor with a transport candidate.
*/
public Candidate(final TransportCandidate tc) {
super(tc);
}
/**
* Get the elements of this candidate.
*/
protected String getChildElements() {
StringBuilder buf = new StringBuilder();
if (transportCandidate != null) {// && transportCandidate instanceof ICECandidate) {
ICECandidate tci = (ICECandidate) transportCandidate;
// We convert the transportElement candidate to XML here...
buf.append(" generation=\"").append(tci.getGeneration()).append("\"");
buf.append(" ip=\"").append(tci.getIp()).append("\"");
buf.append(" port=\"").append(tci.getPort()).append("\"");
buf.append(" network=\"").append(tci.getNetwork()).append("\"");
buf.append(" username=\"").append(tci.getUsername()).append("\"");
buf.append(" password=\"").append(tci.getPassword()).append("\"");
buf.append(" preference=\"").append(tci.getPreference()).append("\"");
buf.append(" type=\"").append(tci.getType()).append("\"");
// Optional elements
if (transportCandidate.getName() != null) {
buf.append(" name=\"").append(tci.getName()).append("\"");
}
}
return buf.toString();
}
}
}
/**
* Raw UDP profile.
*/
public static class RawUdp extends JingleTransport {
public static final String NAMESPACE = "http://www.xmpp.org/extensions/xep-0177.html#ns";
public RawUdp() {
super();
setNamespace(NAMESPACE);
}
/**
* Add a transport candidate
*
* @see org.jivesoftware.smackx.packet.JingleTransport#addCandidate(org.jivesoftware.smackx.packet.JingleTransport.JingleTransportCandidate)
*/
public void addCandidate(final JingleTransportCandidate candidate) {
candidates.clear();
super.addCandidate(candidate);
}
/**
* Get the list of candidates. As a "raw-udp" transport can only contain
* one candidate, we use the first in the list...
*
* @see org.jivesoftware.smackx.packet.JingleTransport#getCandidates()
*/
public List<JingleTransportCandidate> getCandidatesList() {
List<JingleTransportCandidate> copy = new ArrayList<JingleTransportCandidate>();
List<JingleTransportCandidate> superCandidatesList = super.getCandidatesList();
if (superCandidatesList.size() > 0) {
copy.add(superCandidatesList.get(0));
}
return copy;
}
/**
* Raw-udp transport candidate.
*/
public static class Candidate extends JingleTransportCandidate {
/**
* Default constructor
*/
public Candidate() {
super();
}
/**
* Constructor with a transport candidate.
*/
public Candidate(final TransportCandidate tc) {
super(tc);
}
/**
* Get the elements of this candidate.
*/
protected String getChildElements() {
StringBuilder buf = new StringBuilder();
if (transportCandidate != null && transportCandidate instanceof TransportCandidate.Fixed) {
TransportCandidate.Fixed tcf = (TransportCandidate.Fixed) transportCandidate;
buf.append(" generation=\"").append(tcf.getGeneration()).append("\"");
buf.append(" ip=\"").append(tcf.getIp()).append("\"");
buf.append(" port=\"").append(tcf.getPort()).append("\"");
// Optional parameters
String name = tcf.getName();
if (name != null) {
buf.append(" name=\"").append(name).append("\"");
}
}
return buf.toString();
}
}
}
}