001/** 002 * 003 * Copyright © 2014 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 */ 017package org.jivesoftware.smack.sm.packet; 018 019import org.jivesoftware.smack.packet.FullStreamElement; 020import org.jivesoftware.smack.packet.ExtensionElement; 021import org.jivesoftware.smack.packet.XMPPError; 022import org.jivesoftware.smack.util.XmlStringBuilder; 023 024public class StreamManagement { 025 public static final String NAMESPACE = "urn:xmpp:sm:3"; 026 027 public static class StreamManagementFeature implements ExtensionElement { 028 029 public static final String ELEMENT = "sm"; 030 public static final StreamManagementFeature INSTANCE = new StreamManagementFeature(); 031 032 private StreamManagementFeature() { 033 } 034 035 @Override 036 public String getElementName() { 037 return ELEMENT; 038 } 039 040 @Override 041 public String getNamespace() { 042 return NAMESPACE; 043 } 044 045 @Override 046 public CharSequence toXML() { 047 XmlStringBuilder xml = new XmlStringBuilder(this); 048 xml.closeEmptyElement(); 049 return xml; 050 } 051 } 052 053 private static abstract class AbstractEnable extends FullStreamElement { 054 055 /** 056 * Preferred maximum resumption time in seconds (optional). 057 */ 058 protected int max = -1; 059 060 protected boolean resume = false; 061 062 protected void maybeAddResumeAttributeTo(XmlStringBuilder xml) { 063 if (resume) { 064 // XEP 198 never mentions the case where resume='false', it's either set to true or 065 // not set at all. We reflect this in this code part 066 xml.attribute("resume", "true"); 067 } 068 } 069 070 protected void maybeAddMaxAttributeTo(XmlStringBuilder xml) { 071 if (max > 0) { 072 xml.attribute("max", Integer.toString(max)); 073 } 074 } 075 076 public boolean isResumeSet() { 077 return resume; 078 } 079 080 /** 081 * Return the max resumption time in seconds. 082 * @return the max resumption time in seconds 083 */ 084 public int getMaxResumptionTime() { 085 return max; 086 } 087 088 @Override 089 public final String getNamespace() { 090 return NAMESPACE; 091 } 092 } 093 094 public static class Enable extends AbstractEnable { 095 public static final String ELEMENT = "enable"; 096 097 public static final Enable INSTANCE = new Enable(); 098 099 private Enable() { 100 } 101 102 public Enable(boolean resume) { 103 this.resume = resume; 104 } 105 106 public Enable(boolean resume, int max) { 107 this(resume); 108 this.max = max; 109 } 110 111 @Override 112 public CharSequence toXML() { 113 XmlStringBuilder xml = new XmlStringBuilder(this); 114 maybeAddResumeAttributeTo(xml); 115 maybeAddMaxAttributeTo(xml); 116 xml.closeEmptyElement(); 117 return xml; 118 } 119 120 @Override 121 public String getElementName() { 122 return ELEMENT; 123 } 124 } 125 126 /** 127 * A Stream Management 'enabled' element. 128 * <p> 129 * Here is a full example, all attributes besides 'xmlns' are optional. 130 * </p> 131 * <pre> 132 * {@code 133 * <enabled xmlns='urn:xmpp:sm:3' 134 * id='some-long-sm-id' 135 * location='[2001:41D0:1:A49b::1]:9222' 136 * resume='true'/> 137 * } 138 * </pre> 139 */ 140 public static class Enabled extends AbstractEnable { 141 public static final String ELEMENT = "enabled"; 142 143 /** 144 * The stream id ("SM-ID") 145 */ 146 private final String id; 147 148 /** 149 * The location where the server prefers reconnection. 150 */ 151 private final String location; 152 153 public Enabled(String id, boolean resume) { 154 this(id, resume, null, -1); 155 } 156 157 public Enabled(String id, boolean resume, String location, int max) { 158 this.id = id; 159 this.resume = resume; 160 this.location = location; 161 this.max = max; 162 } 163 164 public String getId() { 165 return id; 166 } 167 168 public String getLocation() { 169 return location; 170 } 171 172 @Override 173 public CharSequence toXML() { 174 XmlStringBuilder xml = new XmlStringBuilder(this); 175 xml.optAttribute("id", id); 176 maybeAddResumeAttributeTo(xml); 177 xml.optAttribute("location", location); 178 maybeAddMaxAttributeTo(xml); 179 xml.closeEmptyElement(); 180 return xml; 181 } 182 183 @Override 184 public String getElementName() { 185 return ELEMENT; 186 } 187 } 188 189 public static class Failed extends FullStreamElement { 190 public static final String ELEMENT = "failed"; 191 192 private XMPPError.Condition condition; 193 194 public Failed() { 195 } 196 197 public Failed(XMPPError.Condition condition) { 198 this.condition = condition; 199 } 200 201 public XMPPError.Condition getXMPPErrorCondition() { 202 return condition; 203 } 204 205 @Override 206 public CharSequence toXML() { 207 XmlStringBuilder xml = new XmlStringBuilder(this); 208 if (condition != null) { 209 xml.rightAngleBracket(); 210 xml.append(condition.toString()); 211 xml.xmlnsAttribute(XMPPError.NAMESPACE); 212 xml.closeElement(ELEMENT); 213 } 214 else { 215 xml.closeEmptyElement(); 216 } 217 return xml; 218 } 219 220 @Override 221 public String getNamespace() { 222 return NAMESPACE; 223 } 224 225 @Override 226 public String getElementName() { 227 return ELEMENT; 228 } 229 230 } 231 232 private static abstract class AbstractResume extends FullStreamElement { 233 234 private final long handledCount; 235 private final String previd; 236 237 public AbstractResume(long handledCount, String previd) { 238 this.handledCount = handledCount; 239 this.previd = previd; 240 } 241 242 public long getHandledCount() { 243 return handledCount; 244 } 245 246 public String getPrevId() { 247 return previd; 248 } 249 250 @Override 251 public final String getNamespace() { 252 return NAMESPACE; 253 } 254 255 @Override 256 public final XmlStringBuilder toXML() { 257 XmlStringBuilder xml = new XmlStringBuilder(this); 258 xml.attribute("h", Long.toString(handledCount)); 259 xml.attribute("previd", previd); 260 xml.closeEmptyElement(); 261 return xml; 262 } 263 } 264 265 public static class Resume extends AbstractResume { 266 public static final String ELEMENT = "resume"; 267 268 public Resume(long handledCount, String previd) { 269 super(handledCount, previd); 270 } 271 272 @Override 273 public String getElementName() { 274 return ELEMENT; 275 } 276 } 277 278 public static class Resumed extends AbstractResume { 279 public static final String ELEMENT = "resumed"; 280 281 public Resumed(long handledCount, String previd) { 282 super(handledCount, previd); 283 } 284 285 @Override 286 public String getElementName() { 287 return ELEMENT; 288 } 289 } 290 291 public static class AckAnswer extends FullStreamElement { 292 public static final String ELEMENT = "a"; 293 294 private final long handledCount; 295 296 public AckAnswer(long handledCount) { 297 this.handledCount = handledCount; 298 } 299 300 public long getHandledCount() { 301 return handledCount; 302 } 303 304 @Override 305 public CharSequence toXML() { 306 XmlStringBuilder xml = new XmlStringBuilder(this); 307 xml.attribute("h", Long.toString(handledCount)); 308 xml.closeEmptyElement(); 309 return xml; 310 } 311 312 @Override 313 public String getNamespace() { 314 return NAMESPACE; 315 } 316 317 @Override 318 public String getElementName() { 319 return ELEMENT; 320 } 321 } 322 323 public static class AckRequest extends FullStreamElement { 324 public static final String ELEMENT = "r"; 325 public static final AckRequest INSTANCE = new AckRequest(); 326 327 private AckRequest() { 328 } 329 330 @Override 331 public CharSequence toXML() { 332 return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>"; 333 } 334 335 @Override 336 public String getNamespace() { 337 return NAMESPACE; 338 } 339 340 @Override 341 public String getElementName() { 342 return ELEMENT; 343 } 344 } 345}