aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/service
diff options
context:
space:
mode:
authorBoris Grozev <boris@jitsi.org>2013-06-24 13:32:35 +0300
committerBoris Grozev <boris@jitsi.org>2013-06-24 13:33:23 +0300
commite1eabb5ca84d9fac35eed8d5401b8ac809d32b17 (patch)
tree4ab0e6a7ba12e4611cbafcd81017e4033e699d8c /src/net/java/sip/communicator/service
parent2d368ec9914a6b4f0dd14d8454f35e05b878b2c6 (diff)
downloadjitsi-e1eabb5ca84d9fac35eed8d5401b8ac809d32b17.zip
jitsi-e1eabb5ca84d9fac35eed8d5401b8ac809d32b17.tar.gz
jitsi-e1eabb5ca84d9fac35eed8d5401b8ac809d32b17.tar.bz2
Moves ConferenceInfoDocument to the net.java.sip.communicator.service.protocol.media package.
Diffstat (limited to 'src/net/java/sip/communicator/service')
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/ConferenceInfoDocument.java1270
-rw-r--r--src/net/java/sip/communicator/service/protocol/media/protocol.media.manifest.mf4
2 files changed, 1274 insertions, 0 deletions
diff --git a/src/net/java/sip/communicator/service/protocol/media/ConferenceInfoDocument.java b/src/net/java/sip/communicator/service/protocol/media/ConferenceInfoDocument.java
new file mode 100644
index 0000000..b9ed5e4
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/media/ConferenceInfoDocument.java
@@ -0,0 +1,1270 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol.media;
+
+import net.java.sip.communicator.util.*;
+import org.jitsi.util.xml.*;
+import org.w3c.dom.*;
+
+import javax.xml.parsers.*;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.stream.*;
+import java.io.*;
+import java.util.*;
+
+/**
+ * A class that represents a Conference Information XML document as defined in
+ * RFC4575. It wraps around a DOM <tt>Document</tt> providing convenience
+ * functions.
+ *
+ * {@link "http://tools.ietf.org/html/rfc4575"}
+ *
+ * @author Boris Grozev
+ * @author Sebastien Vincent
+ */
+public class ConferenceInfoDocument
+{
+ /**
+ * The <tt>Logger</tt> used by the <tt>ConferenceInfoDocument</tt> class
+ * and its instances for logging output.
+ */
+ private static final Logger logger
+ = Logger.getLogger(ConferenceInfoDocument.class);
+
+ /**
+ * The namespace of the conference-info element.
+ */
+ public static final String NAMESPACE
+ = "urn:ietf:params:xml:ns:conference-info";
+
+ /**
+ * The name of the "conference-info" element.
+ */
+ public static final String CONFERENCE_INFO_ELEMENT_NAME = "conference-info";
+
+ /**
+ * The name of the "conference-description" element.
+ */
+ public static final String CONFERENCE_DESCRIPTION_ELEMENT_NAME
+ = "conference-description";
+
+ /**
+ * The name of the "conference-state" element.
+ */
+ public static final String CONFERENCE_STATE_ELEMENT_NAME
+ = "conference-state";
+
+ /**
+ * The name of the "state" attribute.
+ */
+ public static final String STATE_ATTR_NAME = "state";
+
+ /**
+ * The name of the "entity" attribute.
+ */
+ public static final String ENTITY_ATTR_NAME = "entity";
+
+ /**
+ * The name of the "version" attribute.
+ */
+ public static final String VERSION_ATTR_NAME = "version";
+
+ /**
+ * The name of the "user" element.
+ */
+ public static final String USER_ELEMENT_NAME = "user";
+
+ /**
+ * The name of the "users" element.
+ */
+ public static final String USERS_ELEMENT_NAME = "users";
+
+ /**
+ * The name of the "endpoint" element.
+ */
+ public static final String ENDPOINT_ELEMENT_NAME = "endpoint";
+
+ /**
+ * The name of the "media" element.
+ */
+ public static final String MEDIA_ELEMENT_NAME = "media";
+
+ /**
+ * The name of the "id" attribute.
+ */
+ public static final String ID_ATTR_NAME = "id";
+
+ /**
+ * The name of the "status" element.
+ */
+ public static final String STATUS_ELEMENT_NAME = "status";
+
+ /**
+ * The name of the "src-id" element.
+ */
+ public static final String SRC_ID_ELEMENT_NAME = "src-id";
+
+ /**
+ * The name of the "type" element.
+ */
+ public static final String TYPE_ELEMENT_NAME = "type";
+
+ /**
+ * The name of the "user-count" element.
+ */
+ public static final String USER_COUNT_ELEMENT_NAME = "user-count";
+
+ /**
+ * The mane of the "display-text" element.
+ */
+ public static final String DISPLAY_TEXT_ELEMENT_NAME = "display-text";
+
+ /**
+ * The <tt>Document</tt> object that we wrap around.
+ */
+ private Document document;
+
+ /**
+ * The single <tt>conference-info</tt> element of <tt>document</tt>
+ */
+ private Element conferenceInfo;
+
+ /**
+ * The <tt>conference-description</tt> child element of
+ * <tt>conference-info</tt>.
+ */
+ private Element conferenceDescription;
+
+ /**
+ * The <tt>conference-state</tt> child element of <tt>conference-info</tt>.
+ */
+ private Element conferenceState;
+
+ /**
+ * The <tt>conference-state</tt> child element of <tt>conference-state</tt>.
+ */
+ private Element userCount;
+
+ /**
+ * The <tt>users</tt> child element of <tt>conference-info</tt>.
+ */
+ private Element users;
+
+ /**
+ * A list of <tt>User</tt>s representing the children of <tt>users</tt>
+ */
+ private final List<User> usersList = new LinkedList<User>();
+
+ /**
+ * Creates a new <tt>ConferenceInfoDocument</tt> instance.
+ */
+ public ConferenceInfoDocument()
+ throws Exception
+ {
+ try
+ {
+ document = XMLUtils.createDocument();
+ }
+ catch (Exception e)
+ {
+ logger.error("Failed to create a new document.", e);
+ throw(e);
+ }
+
+
+ conferenceInfo = document
+ .createElementNS(NAMESPACE, CONFERENCE_INFO_ELEMENT_NAME);
+ document.appendChild(conferenceInfo);
+
+ setVersion(1);
+
+ conferenceDescription
+ = document.createElement(CONFERENCE_DESCRIPTION_ELEMENT_NAME);
+ conferenceInfo.appendChild(conferenceDescription);
+
+ conferenceState = document.createElement(CONFERENCE_STATE_ELEMENT_NAME);
+ conferenceInfo.appendChild(conferenceState);
+ setUserCount(0);
+
+ users = document.createElement(USERS_ELEMENT_NAME);
+ conferenceInfo.appendChild(users);
+ }
+
+ /**
+ * Creates a new <tt>ConferenceInfoDocument</tt> instance and populates it
+ * by parsing the XML in <tt>xml</tt>
+ *
+ * @param xml the XML string to parse
+ */
+ public ConferenceInfoDocument(String xml) throws Exception
+ {
+ byte[] bytes;
+
+ try
+ {
+ bytes = xml.getBytes("UTF-8");
+ }
+ catch (UnsupportedEncodingException uee)
+ {
+ logger.warn(
+ "Failed to gets bytes from String for the UTF-8 charset",
+ uee);
+ bytes = xml.getBytes();
+ }
+
+ try
+ {
+ document
+ = DocumentBuilderFactory.newInstance().newDocumentBuilder()
+ .parse(new ByteArrayInputStream(bytes));
+ }
+ catch (Exception e)
+ {
+ logger.error("Failed to parse conference-info XML", e);
+ throw(e);
+ }
+
+ conferenceInfo = document.getDocumentElement();
+ if (conferenceInfo == null)
+ {
+ throw(new Exception("Could not parse conference-info document,"
+ + " conference-info element not found"));
+ }
+
+ conferenceDescription = XMLUtils
+ .findChild(conferenceInfo, CONFERENCE_DESCRIPTION_ELEMENT_NAME);
+ //conference-description is mandatory
+ if (conferenceDescription == null)
+ {
+ throw(new Exception("Could not parse conference-info document,"
+ + " conference-description element not found"));
+ }
+
+ conferenceState
+ = XMLUtils.findChild(conferenceInfo, CONFERENCE_STATE_ELEMENT_NAME);
+ if (conferenceState != null)
+ userCount = XMLUtils
+ .findChild(conferenceState, USER_COUNT_ELEMENT_NAME);
+
+ users = XMLUtils.findChild(conferenceInfo, USERS_ELEMENT_NAME);
+ if (users == null)
+ {
+ throw(new Exception("Could not parse conference-info document,"
+ + " 'users' element not found"));
+ }
+ NodeList usersNodeList = users.getElementsByTagName(USER_ELEMENT_NAME);
+ for(int i=0; i<usersNodeList.getLength(); i++)
+ {
+ User user = new User((Element)usersNodeList.item(i));
+ usersList.add(user);
+ }
+ }
+
+ /**
+ * Returns the value of the <tt>version</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * @return the value of the <tt>version</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ */
+ public int getVersion()
+ {
+ String versionString = conferenceInfo.getAttribute(VERSION_ATTR_NAME);
+ int version = -1;
+ try
+ {
+ version = Integer.parseInt(versionString);
+ }
+ catch (Exception e){}
+
+ return version;
+ }
+
+ /**
+ * Sets the <tt>version</tt> attribute of the <tt>conference-info</tt>
+ * element.
+ * @param version the value to set the <tt>version</tt> attribute of the
+ * <tt>conference-info</tt> element to.
+ */
+ public void setVersion(int version)
+ {
+ conferenceInfo.setAttribute(VERSION_ATTR_NAME, Integer.toString(version));
+ }
+
+ /**
+ * Gets the value of the <tt>state</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * @return the value of the <tt>state</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ */
+ public State getState()
+ {
+ return getState(conferenceInfo);
+ }
+
+ /**
+ * Returns the value of the <tt>state</tt> attribute of the <tt>users</tt>
+ * child of the <tt>conference-info</tt> element.
+ *
+ * @return the value of the <tt>state</tt> attribute of the <tt>users</tt>
+ * child of the <tt>conference-info</tt> element.
+ */
+ public State getUsersState()
+ {
+ return getState(users);
+ }
+
+ /**
+ * Sets the value of the <tt>state</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * @param state the value to set the <tt>state</tt> attribute of the
+ * <tt>conference-info</tt> element to.
+ */
+ public void setState(State state)
+ {
+ setState(conferenceInfo, state);
+ }
+
+ /**
+ * Sets the value of the <tt>sid</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * This is not part of RFC4575 and is here because we are temporarily using
+ * it in our XMPP implementation.
+ * TODO: remote it when we define another way to handle the Jingle SID
+ *
+ * @param sid the value to set the <tt>sid</tt> attribute of the
+ * <tt>conference-info</tt> element to.
+ */
+ public void setSid(String sid)
+ {
+ conferenceInfo.setAttribute("sid", sid);
+ }
+
+ /**
+ * Sets the value of the <tt>entity</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * @param entity the value to set the <tt>entity</tt> attribute of the
+ * <tt>conference-info</tt> document to.
+ */
+ public void setEntity(String entity)
+ {
+ conferenceInfo.setAttribute(ENTITY_ATTR_NAME, entity);
+ }
+
+ /**
+ * Gets the value of the <tt>entity</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ * @return The value of the <tt>entity</tt> attribute of the
+ * <tt>conference-info</tt> element.
+ */
+ public String getEntity()
+ {
+ return conferenceInfo.getAttribute(ENTITY_ATTR_NAME);
+ }
+
+ /**
+ * Sets the content of the <tt>user-count</tt> child element of the
+ * <tt>conference-state</tt> child element of <tt>conference-info</tt>
+ * @param count the value to set the content of <tt>user-count</tt> to
+ */
+ public void setUserCount(int count)
+ {
+ // conference-state and its user-count child aren't mandatory
+ if (userCount != null)
+ {
+ userCount.setTextContent(Integer.toString(count));
+ }
+ else
+ {
+ if (conferenceState == null)
+ {
+ conferenceState
+ = document.createElement(CONFERENCE_STATE_ELEMENT_NAME);
+ conferenceInfo.appendChild(conferenceState);
+ }
+
+ userCount = document.createElement(USER_COUNT_ELEMENT_NAME);
+ userCount.setTextContent(Integer.toString(count));
+ conferenceState.appendChild(userCount);
+ }
+ }
+
+ /**
+ * Returns the content of the <tt>user-count</tt> child of the
+ * <tt>conference-state</tt> child of <tt>conference-info</tt>, parsed as
+ * an integer, if they exist. Returns -1 if either there isn't a
+ * <tt>conference-state</tt> element, it doesn't have a <tt>user-count</tt>
+ * child, or parsing as integer failed.
+ *
+ * @return the content of the <tt>user-count</tt> child of the
+ * <tt>conference-state</tt> child of <tt>conference-info</tt> element.
+ */
+ public int getUserCount()
+ {
+ int ret = -1;
+ try
+ {
+ ret = Integer.parseInt(userCount.getTextContent());
+ }
+ catch (Exception e)
+ {
+ logger.warn("Could not parse user-count field");
+ }
+ return ret;
+ }
+
+ /**
+ * Returns the XML representation of the <tt>conference-info</tt> tree,
+ * or <tt>null</tt> if an error occurs while trying to get it.
+ *
+ * @return the XML representation of the <tt>conference-info</tt> tree,
+ * or <tt>null</tt> if an error occurs while trying to get it.
+ */
+ public String toXml()
+ {
+ try
+ {
+ Transformer transformer
+ = TransformerFactory.newInstance().newTransformer();
+ StringWriter buffer = new StringWriter();
+ transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
+ "yes");
+ transformer.transform(new DOMSource(conferenceInfo),
+ new StreamResult(buffer));
+ return buffer.toString();
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the XML representation of the document (from the
+ * <tt>conference-info</tt> element down), or an error string in case the
+ * XML cannot be generated for some reason.
+ * @return the XML representation of the document or an error string.
+ */
+ @Override
+ public String toString()
+ {
+ String s = toXml();
+ return s == null
+ ? "Could not get conference-info XML"
+ : s;
+ }
+
+ /**
+ * Returns the list of <tt>User</tt> that represents the <tt>user</tt>
+ * children of the <tt>users</tt> child element of <tt>conference-info</tt>
+ * @return the list of <tt>User</tt> that represents the <tt>user</tt>
+ * children of the <tt>users</tt> child element of <tt>conference-info</tt>
+ */
+ public List<User> getUsers()
+ {
+ return usersList;
+ }
+
+ /**
+ * Searches this document's <tt>User</tt>s and returns the one with
+ * <tt>entity</tt> attribute <tt>entity</tt>, or <tt>null</tt> if one
+ * wasn't found.
+ * @param entity The value of the <tt>entity</tt> attribute to search for.
+ * @return the <tt>User</tt> of this document with <tt>entity</tt>
+ * attribute <tt>entity</tt>, or <tt>null</tt> if one wasn't found.
+ * */
+ public User getUser(String entity)
+ {
+ if (entity == null)
+ return null;
+ for(User u : usersList)
+ {
+ if (entity.equals(u.getEntity()))
+ return u;
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new <tt>User</tt> instance, adds it to the document and
+ * returns it.
+ * @param entity The value to use for the <tt>entity</tt> attribute of the
+ * new <tt>User</tt>.
+ * @return the newly created <tt>User</tt> instance.
+ */
+ public User addNewUser(String entity)
+ {
+ Element userElement = document.createElement(USER_ELEMENT_NAME);
+ User user = new User(userElement);
+ user.setEntity(entity);
+
+ users.appendChild(userElement);
+ usersList.add(user);
+
+ return user;
+ }
+
+ /**
+ * Removes a specific <tt>User</tt> (the one with entity <tt>entity</tt>)
+ * from the document.
+ * @param entity the entity of the <tt>User</tt> to remove.
+ */
+ public void removeUser(String entity)
+ {
+ User user = getUser(entity);
+ if (user != null)
+ {
+ usersList.remove(user);
+ users.removeChild(user.userElement);
+ }
+ }
+
+ /**
+ * Returns the <tt>Document</tt> that this instance wraps around.
+ * @return the <tt>Document</tt> that this instance wraps around.
+ */
+ public Document getDocument()
+ {
+ return document;
+ }
+
+ /**
+ * Returns the <tt>State</tt> corresponding to the <tt>state</tt> attribute
+ * of an <tt>Element</tt>. Default to <tt>State.FULL</tt> which is the
+ * RFC4575 default.
+ * @param element the <tt>Element</tt>
+ * @return the <tt>State</tt> corresponding to the <tt>state</tt> attribute
+ * of an <tt>Element</tt>.
+ */
+ private State getState(Element element)
+ {
+ State state = State.parseString(element.getAttribute(STATE_ATTR_NAME));
+ return state == null
+ ? State.FULL
+ : state;
+ }
+
+ /**
+ * Sets the "state" attribute of <tt>element</tt> to <tt>state</tt>.
+ * If <tt>state</tt> is <tt>State.FULL</tt> removes the "state" attribute,
+ * because this is the default value.
+ * @param element The <tt>Element</tt> for which to set the "state"
+ * attribute of.
+ * @param state the <tt>State</tt> which to set.
+ */
+ private void setState(Element element, State state)
+ {
+ if (element != null)
+ {
+ if (state == State.FULL)
+ element.removeAttribute(STATE_ATTR_NAME);
+ else
+ element.setAttribute(STATE_ATTR_NAME, state.toString());
+ }
+ }
+
+ /**
+ * Sets the <tt>status</tt> child element of <tt>element</tt>. If
+ * <tt>statusString</tt> is <tt>null</tt>, the child element is removed
+ * if present.
+ * @param element the <tt>Element</tt> for which to set the <tt>status</tt>
+ * child element.
+ * @param statusString the <tt>String</tt> to use for the text content of
+ * the <tt>status</tt> element
+ */
+ private void setStatus(Element element, String statusString)
+ {
+ Element statusElement
+ = XMLUtils.findChild(element, STATUS_ELEMENT_NAME);
+ if (statusString == null)
+ {
+ if(statusElement == null)
+ return;
+ else
+ element.removeChild(statusElement);
+ }
+ else
+ {
+ if (statusElement == null)
+ {
+ statusElement = document.createElement(STATUS_ELEMENT_NAME);
+ element.appendChild(statusElement);
+ }
+ statusElement.setTextContent(statusString);
+ }
+ }
+
+ /**
+ * Represents the possible values for the <tt>state</tt> attribute (see
+ * RFC4575)
+ */
+ public enum State
+ {
+ /**
+ * State <tt>full</tt>
+ */
+ FULL("full"),
+
+ /**
+ * State <tt>partial</tt>
+ */
+ PARTIAL("partial"),
+
+ /**
+ * State <tt>deleted</tt>
+ */
+ DELETED("deleted");
+
+ /**
+ * The name of this <tt>State</tt>
+ */
+ private String name;
+
+ /**
+ * Creates a <tt>State</tt> instance with the specified name.
+ * @param name
+ */
+ private State(String name)
+ {
+ this.name = name;
+ }
+
+ /**
+ * Returns the name of this <tt>State</tt>
+ * @return the name of this <tt>State</tt>
+ */
+ @Override
+ public String toString()
+ {
+ return name;
+ }
+
+ /**
+ * Returns a <tt>State</tt> value corresponding to the specified
+ * <tt>name</tt>
+ * @return a <tt>State</tt> value corresponding to the specified
+ * <tt>name</tt>
+ */
+ public static State parseString(String name)
+ {
+ if (FULL.toString().equals(name))
+ return FULL;
+ else if(PARTIAL.toString().equals(name))
+ return PARTIAL;
+ else if(DELETED.toString().equals(name))
+ return DELETED;
+ else
+ return null;
+ }
+ }
+
+ /**
+ * Wraps around an <tt>Element</tt> and represents a <tt>user</tt>
+ * element (child of the <tt>users</tt> element). See RFC4575.
+ */
+ public class User
+ {
+ /**
+ * The underlying <tt>Element</tt>.
+ */
+ private Element userElement;
+
+ /**
+ * The list of <tt>Endpoint</tt>s representing the <tt>endpoint</tt>
+ * children of this <tt>User</tt>'s element.
+ */
+ private List<Endpoint> endpointsList = new LinkedList<Endpoint>();
+
+ /**
+ * Creates a new <tt>User</tt> instance with the specified
+ * <tt>Element</tt> as its underlying element.
+ * @param user the <tt>Element</tt> to use
+ */
+ private User(Element user)
+ {
+ this.userElement = user;
+ NodeList endpointsNodeList
+ = user.getElementsByTagName(ENDPOINT_ELEMENT_NAME);
+ for (int i=0; i<endpointsNodeList.getLength(); i++)
+ {
+ Endpoint endpoint
+ = new Endpoint((Element)endpointsNodeList.item(i));
+ endpointsList.add(endpoint);
+ }
+ }
+
+ /**
+ * Sets the <tt>entity</tt> attribute of this <tt>User</tt>'s element
+ * to <tt>entity</tt>
+ * @param entity the value to set for the <tt>entity</tt> attribute.
+ */
+ public void setEntity(String entity)
+ {
+ userElement.setAttribute(ENTITY_ATTR_NAME, entity);
+ }
+
+ /**
+ * Returns the value of the <tt>entity</tt> attribute of this
+ * <tt>User</tt>'s element.
+ * @return the value of the <tt>entity</tt> attribute of this
+ * <tt>User</tt>'s element.
+ */
+ public String getEntity()
+ {
+ return userElement.getAttribute(ENTITY_ATTR_NAME);
+ }
+
+ /**
+ * Sets the <tt>state</tt> attribute of this <tt>User</tt>'s element to
+ * <tt>state</tt>
+ * @param state the value to use for the <tt>state</tt> attribute.
+ */
+ public void setState(State state)
+ {
+ ConferenceInfoDocument.this.setState(userElement, state);
+ }
+
+ /**
+ * Returns the value of the <tt>state</tt> attribute of this
+ * <tt>User</tt>'s element
+ * @return the value of the <tt>state</tt> attribute of this
+ * <tt>User</tt>'s element
+ */
+ public State getState()
+ {
+ return ConferenceInfoDocument.this.getState(userElement);
+ }
+
+ /**
+ * Sets the <tt>display-text</tt> child element to this <tt>User</tt>'s
+ * element.
+ * @param text the text content to use for the <tt>display-text</tt>
+ * element.
+ */
+ public void setDisplayText(String text)
+ {
+ Element displayText
+ = XMLUtils.findChild(userElement, DISPLAY_TEXT_ELEMENT_NAME);
+ if (text == null || text.equals(""))
+ {
+ if (displayText == null)
+ return;
+ else
+ userElement.removeChild(displayText);
+ }
+ else
+ {
+ if (displayText == null)
+ {
+ displayText
+ = document.createElement(DISPLAY_TEXT_ELEMENT_NAME);
+ userElement.appendChild(displayText);
+ }
+ displayText.setTextContent(text);
+ }
+ }
+
+ /**
+ * Returns the text content of the <tt>display-text</tt> child element
+ * of this <tt>User</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ * @return the text content of the <tt>display-text</tt> child element
+ * of this <tt>User</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ */
+ public String getDisplayText()
+ {
+ Element displayText
+ = XMLUtils.findChild(userElement, DISPLAY_TEXT_ELEMENT_NAME);
+ if (displayText != null)
+ return displayText.getTextContent();
+
+ return null;
+ }
+
+ /**
+ * Returns the list of <tt>Endpoint</tt>s which represent the
+ * <tt>endpoint</tt> children of this <tt>User</tt>'s element.
+ * @return the list of <tt>Endpoint</tt>s which represent the
+ * <tt>endpoint</tt> children of this <tt>User</tt>'s element.
+ */
+ public List<Endpoint> getEndpoints()
+ {
+ return endpointsList;
+ }
+
+ /**
+ * Searches this <tt>User</tt>'s associated <tt>Endpoint</tt>s
+ * and returns the one with <tt>entity</tt> attribute <tt>entity</tt>,
+ * or <tt>null</tt> if one wasn't found.
+ * @param entity The value of the <tt>entity</tt> attribute to search
+ * for.
+ * @return The <tt>Endpoint</tt> with <tt>entity</tt> attribute
+ * <tt>entity</tt>, or <tt>null</tt> if one wasn't found.
+ */
+ public Endpoint getEndpoint(String entity)
+ {
+ if (entity == null)
+ return null;
+ for (Endpoint e : endpointsList)
+ {
+ if (entity.equals(e.getEntity()))
+ return e;
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new <tt>Endpoint</tt> instance, adds it to this
+ * <tt>User</tt> and returns it.
+ * @param entity The value to use for the <tt>entity</tt> attribute of
+ * the new <tt>Endpoint</tt>.
+ * @return the newly created <tt>Endpoint</tt> instance.
+ */
+ public Endpoint addNewEndpoint(String entity)
+ {
+ Element endpointElement
+ = document.createElement(ENDPOINT_ELEMENT_NAME);
+ Endpoint endpoint = new Endpoint(endpointElement);
+ endpoint.setEntity(entity);
+
+ userElement.appendChild(endpointElement);
+ endpointsList.add(endpoint);
+
+ return endpoint;
+ }
+
+ /**
+ * Removes a specific <tt>Endpoint</tt> (the one with entity
+ * <tt>entity</tt>) from this <tt>User</tt>.
+ * @param entity the <tt>entity</tt> of the <tt>Endpoint</tt> to remove
+ */
+ public void removeEndpoint(String entity)
+ {
+ Endpoint endpoint = getEndpoint(entity);
+ if (endpoint != null)
+ {
+ endpointsList.remove(endpoint);
+ userElement.removeChild(endpoint.endpointElement);
+ }
+ }
+ }
+
+ /**
+ * Wraps around an <tt>Element</tt> and represents an <tt>endpoint</tt>
+ * element. See RFC4575.
+ */
+ public class Endpoint
+ {
+ /**
+ * The underlying <tt>Element</tt>.
+ */
+ private Element endpointElement;
+
+ /**
+ * The list of <tt>Media</tt>s representing the <tt>media</tt>
+ * children elements of this <tt>Endpoint</tt>'s element.
+ */
+ private List<Media> mediasList = new LinkedList<Media>();
+
+ /**
+ * Creates a new <tt>Endpoint</tt> instance with the specified
+ * <tt>Element</tt> as its underlying element.
+ * @param endpoint the <tt>Element</tt> to use
+ */
+ private Endpoint(Element endpoint)
+ {
+ this.endpointElement = endpoint;
+ NodeList mediaNodeList
+ = endpoint.getElementsByTagName(MEDIA_ELEMENT_NAME);
+ for (int i=0; i<mediaNodeList.getLength(); i++)
+ {
+ Media media = new Media((Element)mediaNodeList.item(i));
+ mediasList.add(media);
+ }
+ }
+
+ /**
+ * Sets the <tt>entity</tt> attribute of this <tt>Endpoint</tt>'s
+ * element to <tt>entity</tt>
+ * @param entity the value to set for the <tt>entity</tt> attribute.
+ */
+ public void setEntity(String entity)
+ {
+ endpointElement.setAttribute(ENTITY_ATTR_NAME, entity);
+ }
+
+ /**
+ * Returns the <tt>entity</tt> attribute of this <tt>Endpoint</tt>'s
+ * element.
+ * @return the <tt>entity</tt> attribute of this <tt>Endpoint</tt>'s
+ * element.
+ */
+ public String getEntity()
+ {
+ return endpointElement.getAttribute(ENTITY_ATTR_NAME);
+ }
+
+ /**
+ * Sets the <tt>state</tt> attribute of this <tt>User</tt>'s element to
+ * <tt>state</tt>
+ * @param state the value to use for the <tt>state</tt> attribute.
+ */
+ public void setState(State state)
+ {
+ ConferenceInfoDocument.this.setState(endpointElement, state);
+ }
+
+ /**
+ * Returns the value of the <tt>state</tt> attribute of this
+ * <tt>Endpoint</tt>'s element
+ * @return the value of the <tt>state</tt> attribute of this
+ * <tt>Endpoint</tt>'s element
+ */
+ public State getState()
+ {
+ return ConferenceInfoDocument.this.getState(endpointElement);
+ }
+
+ /**
+ * Sets the <tt>status</tt> child element of this <tt>Endpoint</tt>'s
+ * element.
+ * @param status the value to be used for the text content of the
+ * <tt>status</tt> element.
+ */
+ public void setStatus(EndpointStatusType status)
+ {
+ ConferenceInfoDocument.this.setStatus(endpointElement,
+ status == null
+ ? null
+ : status.toString());
+ }
+
+ /**
+ * Returns the <tt>EndpointStatusType</tt> corresponding to the
+ * <tt>status</tt> child of this <tt>Endpoint</tt>'s element, or
+ * <tt>null</tt>.
+ * @return the <tt>EndpointStatusType</tt> corresponding to the
+ * <tt>status</tt> child of this <tt>Endpoint</tt>'s element, or
+ * <tt>null</tt>.
+ */
+ public EndpointStatusType getStatus()
+ {
+ Element statusElement
+ = XMLUtils.findChild(endpointElement, STATUS_ELEMENT_NAME);
+ return statusElement == null
+ ? null
+ : EndpointStatusType.parseString(statusElement.getTextContent());
+ }
+
+ /**
+ * Returns the list of <tt>Media</tt>s which represent the
+ * <tt>media</tt> children of this <tt>Endpoint</tt>'s element.
+ * @return the list of <tt>Media</tt>s which represent the
+ * <tt>media</tt> children of this <tt>Endpoint</tt>'s element.
+ */
+ public List<Media> getMedias()
+ {
+ return mediasList;
+ }
+
+ /**
+ * Searches this <tt>Endpoint</tt>'s associated <tt>Media</tt>s
+ * and returns the one with <tt>id</tt> attribute <tt>id</tt>, or
+ * <tt>null</tt> if one wasn't found.
+ * @param id The value of the <tt>id</tt> attribute to search
+ * for.
+ * @return The <tt>Media</tt>s with <tt>id</tt> attribute <tt>id</tt>,
+ * or <tt>null</tt> if one wasn't found.
+ */
+ public Media getMedia(String id)
+ {
+ if (id == null)
+ return null;
+ for (Media m : mediasList)
+ {
+ if (id.equals(m.getId()))
+ return m;
+ }
+ return null;
+ }
+
+ /**
+ * Creates a new <tt>Media</tt> instance, adds it to this
+ * <tt>Endpoint</tt> and returns it.
+ * @param id The value to use for the <tt>id</tt> attribute of the
+ * new <tt>Media</tt>'s element.
+ * @return the newly created <tt>Media</tt> instance.
+ */
+ public Media addNewMedia(String id)
+ {
+ Element mediaElement = document.createElement(MEDIA_ELEMENT_NAME);
+ Media media = new Media(mediaElement);
+ media.setId(id);
+
+ endpointElement.appendChild(mediaElement);
+ mediasList.add(media);
+
+ return media;
+ }
+
+ /**
+ * Removes a specific <tt>Media</tt> (the one with id <tt>id</tt>) from
+ * this <tt>Endpoint</tt>.
+ * @param id the <tt>id</tt> of the <tt>Media</tt> to remove.
+ */
+ public void removeMedia(String id)
+ {
+ Media media = getMedia(id);
+ if (media != null)
+ {
+ mediasList.remove(media);
+ endpointElement.removeChild(media.mediaElement);
+ }
+ }
+ }
+
+ /**
+ * Wraps around an <tt>Element</tt> and represents a <tt>media</tt>
+ * element. See RFC4575.
+ */
+ public class Media
+ {
+ /**
+ * The underlying <tt>Element</tt>.
+ */
+ private Element mediaElement;
+
+ /**
+ * Creates a new <tt>Media</tt> instance with the specified
+ * <tt>Element</tt> as its underlying element.
+ * @param media the <tt>Element</tt> to use
+ */
+ private Media(Element media)
+ {
+ this.mediaElement = media;
+ }
+
+ /**
+ * Sets the <tt>id</tt> attribute of this <tt>Media</tt>'s element to
+ * <tt>id</tt>
+ * @param id the value to set for the <tt>id</tt> attribute.
+ */
+ public void setId(String id)
+ {
+ mediaElement.setAttribute(ID_ATTR_NAME, id);
+ }
+
+ /**
+ * Returns the <tt>id</tt> attribute of this <tt>Media</tt>'s element.
+ * @return the <tt>id</tt> attribute of this <tt>Media</tt>'s element.
+ */
+ public String getId()
+ {
+ return mediaElement.getAttribute(ID_ATTR_NAME);
+ }
+
+ /**
+ * Sets the <tt>src-id</tt> child element of this <tt>Media</tt>'s
+ * element.
+ * @param srcId the value to be used for the text content of the
+ * <tt>src-id</tt> element.
+ */
+ public void setSrcId(String srcId)
+ {
+ Element srcIdElement
+ = XMLUtils.findChild(mediaElement, SRC_ID_ELEMENT_NAME);
+ if (srcIdElement == null)
+ {
+ srcIdElement
+ = document.createElement(SRC_ID_ELEMENT_NAME);
+ mediaElement.appendChild(srcIdElement);
+ }
+ srcIdElement.setTextContent(srcId);
+ }
+
+ /**
+ * Returns the text content of the <tt>src-id</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ * @return the text content of the <tt>src-id</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ */
+ public String getSrcId()
+ {
+ Element srcIdElement
+ = XMLUtils.findChild(mediaElement, SRC_ID_ELEMENT_NAME);
+ return srcIdElement == null
+ ? null
+ : srcIdElement.getTextContent();
+ }
+
+ /**
+ * Sets the <tt>type</tt> child element of this <tt>Media</tt>'s
+ * element.
+ * @param type the value to be used for the text content of the
+ * <tt>type</tt> element.
+ */
+ public void setType(String type)
+ {
+ Element typeElement
+ = XMLUtils.findChild(mediaElement, TYPE_ELEMENT_NAME);
+ if (typeElement == null)
+ {
+ typeElement = document.createElement(TYPE_ELEMENT_NAME);
+ mediaElement.appendChild(typeElement);
+ }
+ typeElement.setTextContent(type);
+ }
+
+ /**
+ * Returns the text content of the <tt>type</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ * @return the text content of the <tt>type</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ */
+ public String getType()
+ {
+ Element typeElement
+ = XMLUtils.findChild(mediaElement, TYPE_ELEMENT_NAME);
+ return typeElement == null
+ ? null
+ : typeElement.getTextContent();
+ }
+
+ /**
+ * Sets the <tt>status</tt> child element of this <tt>Media</tt>'s
+ * element.
+ * @param status the value to be used for the text content of the
+ * <tt>status</tt> element.
+ */
+ public void setStatus(String status)
+ {
+ ConferenceInfoDocument.this.setStatus(mediaElement, status);
+ }
+
+ /**
+ * Returns the text content of the <tt>status</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ * @return the text content of the <tt>status</tt> child element
+ * of this <tt>Media</tt>'s element, if it has such a child. Returns
+ * <tt>null</tt> otherwise.
+ */
+ public String getStatus()
+ {
+ Element statusElement
+ = XMLUtils.findChild(mediaElement, STATUS_ELEMENT_NAME);
+ return statusElement == null
+ ? null
+ : statusElement.getTextContent();
+ }
+ }
+
+ /**
+ * Endpoint status type.
+ *
+ * @author Sebastien Vincent
+ */
+ public enum EndpointStatusType
+ {
+ /**
+ * Pending.
+ */
+ pending("pending"),
+
+ /**
+ * Dialing-out.
+ */
+ dialing_out ("dialing-out"),
+
+ /**
+ * Dialing-in.
+ */
+ dialing_in("dialing-in"),
+
+ /**
+ * Alerting.
+ */
+ alerting("alerting"),
+
+ /**
+ * On-hold.
+ */
+ on_hold("on-hold"),
+
+ /**
+ * Connected.
+ */
+ connected("connected"),
+
+ /**
+ * Muted via focus.
+ */
+ muted_via_focus("mute-via-focus"),
+
+ /**
+ * Disconnecting.
+ */
+ disconnecting("disconnecting"),
+
+ /**
+ * Disconnected.
+ */
+ disconnected("disconnected");
+
+ /**
+ * The name of this type.
+ */
+ private final String type;
+
+ /**
+ * Creates a <tt>EndPointType</tt> instance with the specified name.
+ *
+ * @param type type name.
+ */
+ private EndpointStatusType(String type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Returns the type name.
+ *
+ * @return type name
+ */
+ @Override
+ public String toString()
+ {
+ return type;
+ }
+
+ /**
+ * Returns a <tt>EndPointType</tt>.
+ *
+ * @param typeStr the <tt>String</tt> that we'd like to
+ * parse.
+ * @return an EndPointType.
+ *
+ * @throws IllegalArgumentException in case <tt>typeStr</tt> is
+ * not a valid <tt>EndPointType</tt>.
+ */
+ public static EndpointStatusType parseString(String typeStr)
+ throws IllegalArgumentException
+ {
+ for (EndpointStatusType value : values())
+ if (value.toString().equals(typeStr))
+ return value;
+
+ throw new IllegalArgumentException(
+ typeStr + " is not a valid reason");
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/media/protocol.media.manifest.mf b/src/net/java/sip/communicator/service/protocol/media/protocol.media.manifest.mf
index fe14a18..9ecfd1d 100644
--- a/src/net/java/sip/communicator/service/protocol/media/protocol.media.manifest.mf
+++ b/src/net/java/sip/communicator/service/protocol/media/protocol.media.manifest.mf
@@ -5,6 +5,9 @@ Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
System-Bundle: yes
Import-Package: javax.xml.parsers,
+ javax.xml.transform,
+ javax.xml.transform.dom,
+ javax.xml.transform.stream,
net.java.sip.communicator.service.netaddr,
net.java.sip.communicator.service.protocol,
net.java.sip.communicator.service.protocol.event,
@@ -20,6 +23,7 @@ Import-Package: javax.xml.parsers,
org.jitsi.service.protocol,
org.jitsi.util,
org.jitsi.util.event,
+ org.jitsi.util.xml,
org.osgi.framework,
org.w3c.dom,
org.xml.sax