Jingle.java
- /**
- *
- * Copyright 2003-2007 Jive Software, 2014-2022 Florian Schmaus
- *
- * 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.jingle.element;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.List;
- import org.jivesoftware.smack.XMPPConnection;
- import org.jivesoftware.smack.packet.IQ;
- import org.jivesoftware.smack.packet.IqBuilder;
- import org.jivesoftware.smack.packet.IqData;
- import org.jivesoftware.smack.packet.id.StandardStanzaIdSource;
- import org.jivesoftware.smack.util.Objects;
- import org.jivesoftware.smack.util.StringUtils;
- import org.jxmpp.jid.FullJid;
- /**
- * The Jingle element.
- *
- * <h2>Jingle Element Structure</h2>
- * <pre>{@code
- * jingle
- * │ action (REQUIRED, XEP-0166 § 7.2)
- * | content-accept
- * | content-add
- * | content-modify
- * | content-reject
- * | content-remove
- * | description-info
- * | security-info
- * | session-accept
- * | session-info
- * | session-initiate
- * | transport-accept
- * | transport-info
- * | transport-reject
- * | transport-replace
- * │ initiator (RECOMMENDED for session initiate, NOT RECOMMENDED otherwise, full JID, XEP-0166 § 7.1)
- * │ responder (RECOMMENDED for session accept, NOT RECOMMENDED otherwise, full JID. XEP-0166 § 7.1)
- * │ sid (REQUIRED, SHOULD match XML Nmtoken production)
- * │
- * ├── <reason/> (optional, XEP-0166 § 7.4)
- * │ │
- * │ └──(alternative─session│busy│..)
- * │
- * └── <content/> (one or more, XEP-0166 § 7.3)
- * │ creator (REQUIRED, must be one of)
- * | initiator
- * | responder
- * │ disposition (OPTIONAL)
- * │ name (REQUIRED)
- * │ senders (OPTIONAL, except when content-modify then REQUIRED)
- * | both (default)
- * | initiator
- * | none
- * | responder
- * │
- * ├──description
- * │ │ media
- * │ │ xmlns
- * │ │
- * │ ├──payload─type
- * │ │
- * │ └──file (XEP─0234)
- * │
- * └──transport
- * │ xmlns
- * │ pwd (OPTIONAL, XEP-0176 Jingle ICE)
- * │ ufrag (OPTIONAL, XEP-0176 Jingle ICE)
- * │ mode (XEP-0234 Jingle File Transfer)
- * │ sid (XEP-0234 Jingle File Transfer)
- * │
- * └──candidate
- * component
- * foundation
- * generation
- * id
- * ip
- * network
- * port
- * priority
- * protocol
- * type
- * }</pre>
- *
- * @author Florian Schmaus
- */
- public final class Jingle extends IQ {
- public static final String NAMESPACE = "urn:xmpp:jingle:1";
- public static final String ACTION_ATTRIBUTE_NAME = "action";
- public static final String INITIATOR_ATTRIBUTE_NAME = "initiator";
- public static final String RESPONDER_ATTRIBUTE_NAME = "responder";
- public static final String SESSION_ID_ATTRIBUTE_NAME = "sid";
- public static final String ELEMENT = "jingle";
- /**
- * The session ID related to this session. The session ID is a unique identifier generated by the initiator. This
- * should match the XML Nmtoken production so that XML character escaping is not needed for characters such as &.
- */
- private final String sessionId;
- /**
- * The jingle action. This attribute is required.
- */
- private final JingleAction action;
- private final FullJid initiator;
- private final FullJid responder;
- private final JingleReason reason;
- private final List<JingleContent> contents;
- private Jingle(Builder builder, String sessionId, JingleAction action, FullJid initiator, FullJid responder, JingleReason reason,
- List<JingleContent> contents) {
- super(builder, ELEMENT, NAMESPACE);
- this.sessionId = StringUtils.requireNotNullNorEmpty(sessionId, "Jingle session ID must not be null");
- this.action = Objects.requireNonNull(action, "Jingle action must not be null");
- this.initiator = initiator;
- this.responder = responder;
- this.reason = reason;
- if (contents != null) {
- this.contents = Collections.unmodifiableList(contents);
- }
- else {
- this.contents = Collections.emptyList();
- }
- setType(Type.set);
- }
- /**
- * Get the initiator. The initiator will be the full JID of the entity that has initiated the flow (which may be
- * different to the "from" address in the IQ)
- *
- * @return the initiator
- */
- public FullJid getInitiator() {
- return initiator;
- }
- /**
- * Get the responder. The responder is the full JID of the entity that has replied to the initiation (which may be
- * different to the "to" address in the IQ).
- *
- * @return the responder
- */
- public FullJid getResponder() {
- return responder;
- }
- /**
- * Returns the session ID related to the session. The session ID is a unique identifier generated by the initiator.
- * This should match the XML Nmtoken production so that XML character escaping is not needed for characters such as
- * &.
- *
- * @return Returns the session ID related to the session.
- */
- public String getSid() {
- return sessionId;
- }
- /**
- * Get the action specified in the jingle IQ.
- *
- * @return the action.
- */
- public JingleAction getAction() {
- return action;
- }
- public JingleReason getReason() {
- return reason;
- }
- /**
- * Get a List of the contents.
- *
- * @return the contents.
- */
- public List<JingleContent> getContents() {
- return contents;
- }
- /**
- * Get the only jingle content if one exists, or <code>null</code>. This method will throw an
- * {@link IllegalStateException} if there is more than one jingle content.
- *
- * @return a JingleContent instance or <code>null</code>.
- * @throws IllegalStateException if there is more than one jingle content.
- */
- public JingleContent getSoleContentOrThrow() {
- if (contents.isEmpty()) {
- return null;
- }
- if (contents.size() > 1) {
- throw new IllegalStateException();
- }
- return contents.get(0);
- }
- @Override
- protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) {
- xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator());
- xml.optAttribute(RESPONDER_ATTRIBUTE_NAME, getResponder());
- xml.optAttribute(ACTION_ATTRIBUTE_NAME, getAction());
- xml.optAttribute(SESSION_ID_ATTRIBUTE_NAME, getSid());
- xml.rightAngleBracket();
- xml.optElement(reason);
- xml.append(contents);
- return xml;
- }
- /**
- * Deprecated, do not use.
- *
- * @return a builder.
- * @deprecated use {@link #builder(XMPPConnection)} instead.
- */
- @Deprecated
- // TODO: Remove in Smack 4.6.
- public static Builder getBuilder() {
- return builder(StandardStanzaIdSource.DEFAULT.getNewStanzaId());
- }
- public static Builder builder(XMPPConnection connection) {
- return new Builder(connection);
- }
- public static Builder builder(IqData iqData) {
- return new Builder(iqData);
- }
- public static Builder builder(String stanzaId) {
- return new Builder(stanzaId);
- }
- public static final class Builder extends IqBuilder<Builder, Jingle> {
- private String sid;
- private JingleAction action;
- private FullJid initiator;
- private FullJid responder;
- private JingleReason reason;
- private List<JingleContent> contents;
- Builder(IqData iqCommon) {
- super(iqCommon);
- }
- Builder(XMPPConnection connection) {
- super(connection);
- }
- Builder(String stanzaId) {
- super(stanzaId);
- }
- public Builder setSessionId(String sessionId) {
- StringUtils.requireNotNullNorEmpty(sessionId, "Session ID must not be null nor empty");
- this.sid = sessionId;
- return this;
- }
- public Builder setAction(JingleAction action) {
- this.action = action;
- return this;
- }
- public Builder setInitiator(FullJid initator) {
- this.initiator = initator;
- return this;
- }
- public Builder setResponder(FullJid responder) {
- this.responder = responder;
- return this;
- }
- public Builder addJingleContent(JingleContent content) {
- if (contents == null) {
- contents = new ArrayList<>(1);
- }
- contents.add(content);
- return this;
- }
- public Builder setReason(JingleReason.Reason reason) {
- this.reason = new JingleReason(reason);
- return this;
- }
- public Builder setReason(JingleReason reason) {
- this.reason = reason;
- return this;
- }
- @Override
- public Jingle build() {
- return new Jingle(this, sid, action, initiator, responder, reason, contents);
- }
- @Override
- public Builder getThis() {
- return this;
- }
- }
- }