001/** 002 * 003 * Copyright 2003-2007 Jive Software, 2014-2017 Florian Schmaus 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 */ 017 018package org.jivesoftware.smackx.jingle.element; 019 020import java.util.ArrayList; 021import java.util.Collections; 022import java.util.List; 023 024import org.jivesoftware.smack.packet.IQ; 025import org.jivesoftware.smack.util.Objects; 026import org.jivesoftware.smack.util.StringUtils; 027 028import org.jxmpp.jid.FullJid; 029 030/** 031 * The Jingle element. 032 * 033 * @author Florian Schmaus 034 */ 035public final class Jingle extends IQ { 036 037 public static final String NAMESPACE = "urn:xmpp:jingle:1"; 038 039 public static final String ACTION_ATTRIBUTE_NAME = "action"; 040 041 public static final String INITIATOR_ATTRIBUTE_NAME = "initiator"; 042 043 public static final String RESPONDER_ATTRIBUTE_NAME = "responder"; 044 045 public static final String SESSION_ID_ATTRIBUTE_NAME = "sid"; 046 047 public static final String ELEMENT = "jingle"; 048 049 /** 050 * The session ID related to this session. The session ID is a unique identifier generated by the initiator. This 051 * should match the XML Nmtoken production so that XML character escaping is not needed for characters such as &. 052 */ 053 private final String sessionId; 054 055 /** 056 * The jingle action. This attribute is required. 057 */ 058 private final JingleAction action; 059 060 private final FullJid initiator; 061 062 private final FullJid responder; 063 064 private final JingleReason reason; 065 066 private final List<JingleContent> contents; 067 068 private Jingle(String sessionId, JingleAction action, FullJid initiator, FullJid responder, JingleReason reason, 069 List<JingleContent> contents) { 070 super(ELEMENT, NAMESPACE); 071 this.sessionId = StringUtils.requireNotNullOrEmpty(sessionId, "Jingle session ID must not be null"); 072 this.action = Objects.requireNonNull(action, "Jingle action must not be null"); 073 this.initiator = initiator; 074 this.responder = responder; 075 this.reason = reason; 076 if (contents != null) { 077 this.contents = Collections.unmodifiableList(contents); 078 } 079 else { 080 this.contents = Collections.emptyList(); 081 } 082 setType(Type.set); 083 } 084 085 /** 086 * Get the initiator. The initiator will be the full JID of the entity that has initiated the flow (which may be 087 * different to the "from" address in the IQ) 088 * 089 * @return the initiator 090 */ 091 public FullJid getInitiator() { 092 return initiator; 093 } 094 095 /** 096 * Get the responder. The responder is the full JID of the entity that has replied to the initiation (which may be 097 * different to the "to" address in the IQ). 098 * 099 * @return the responder 100 */ 101 public FullJid getResponder() { 102 return responder; 103 } 104 105 /** 106 * Returns the session ID related to the session. The session ID is a unique identifier generated by the initiator. 107 * This should match the XML Nmtoken production so that XML character escaping is not needed for characters such as 108 * &. 109 * 110 * @return Returns the session ID related to the session. 111 */ 112 public String getSid() { 113 return sessionId; 114 } 115 116 /** 117 * Get the action specified in the jingle IQ. 118 * 119 * @return the action. 120 */ 121 public JingleAction getAction() { 122 return action; 123 } 124 125 public JingleReason getReason() { 126 return reason; 127 } 128 129 /** 130 * Get a List of the contents. 131 * 132 * @return the contents. 133 */ 134 public List<JingleContent> getContents() { 135 return contents; 136 } 137 138 /** 139 * Get the only jingle content if one exists, or <code>null</code>. This method will throw an 140 * {@link IllegalStateException} if there is more than one jingle content. 141 * 142 * @return a JingleContent instance or <code>null</code>. 143 * @throws IllegalStateException if there is more than one jingle content. 144 */ 145 public JingleContent getSoleContentOrThrow() { 146 if (contents.isEmpty()) { 147 return null; 148 } 149 150 if (contents.size() > 1) { 151 throw new IllegalStateException(); 152 } 153 154 return contents.get(0); 155 } 156 157 @Override 158 protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { 159 xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator()); 160 xml.optAttribute(RESPONDER_ATTRIBUTE_NAME, getResponder()); 161 xml.optAttribute(ACTION_ATTRIBUTE_NAME, getAction()); 162 xml.optAttribute(SESSION_ID_ATTRIBUTE_NAME, getSid()); 163 xml.rightAngleBracket(); 164 165 xml.optElement(reason); 166 167 xml.append(contents); 168 169 return xml; 170 } 171 172 public static Builder getBuilder() { 173 return new Builder(); 174 } 175 176 public static final class Builder { 177 private String sid; 178 179 private JingleAction action; 180 181 private FullJid initiator; 182 183 private FullJid responder; 184 185 private JingleReason reason; 186 187 private List<JingleContent> contents; 188 189 private Builder() { 190 } 191 192 public Builder setSessionId(String sessionId) { 193 StringUtils.requireNotNullOrEmpty(sessionId, "Session ID must not be null or empty"); 194 this.sid = sessionId; 195 return this; 196 } 197 198 public Builder setAction(JingleAction action) { 199 this.action = action; 200 return this; 201 } 202 203 public Builder setInitiator(FullJid initator) { 204 this.initiator = initator; 205 return this; 206 } 207 208 public Builder setResponder(FullJid responder) { 209 this.responder = responder; 210 return this; 211 } 212 213 public Builder addJingleContent(JingleContent content) { 214 if (contents == null) { 215 contents = new ArrayList<>(1); 216 } 217 contents.add(content); 218 return this; 219 } 220 221 public Builder setReason(JingleReason.Reason reason) { 222 this.reason = new JingleReason(reason); 223 return this; 224 } 225 226 public Builder setReason(JingleReason reason) { 227 this.reason = reason; 228 return this; 229 } 230 231 public Jingle build() { 232 return new Jingle(sid, action, initiator, responder, reason, contents); 233 } 234 } 235}