StreamManagement.java

  1. /**
  2.  *
  3.  * Copyright © 2014-2021 Florian Schmaus
  4.  *
  5.  * Licensed under the Apache License, Version 2.0 (the "License");
  6.  * you may not use this file except in compliance with the License.
  7.  * You may obtain a copy of the License at
  8.  *
  9.  *     http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.jivesoftware.smack.sm.packet;

  18. import java.util.Collections;
  19. import java.util.List;

  20. import javax.xml.namespace.QName;

  21. import org.jivesoftware.smack.packet.ExtensionElement;
  22. import org.jivesoftware.smack.packet.Nonza;
  23. import org.jivesoftware.smack.packet.StanzaError;
  24. import org.jivesoftware.smack.packet.StanzaErrorTextElement;
  25. import org.jivesoftware.smack.util.XmlStringBuilder;

  26. public class StreamManagement {
  27.     public static final String NAMESPACE = "urn:xmpp:sm:3";

  28.     public static final class StreamManagementFeature implements ExtensionElement {

  29.         public static final String ELEMENT = "sm";
  30.         public static final QName QNAME = new QName(NAMESPACE, ELEMENT);

  31.         public static final StreamManagementFeature INSTANCE = new StreamManagementFeature();

  32.         private StreamManagementFeature() {
  33.         }

  34.         @Override
  35.         public String getElementName() {
  36.             return QNAME.getLocalPart();
  37.         }

  38.         @Override
  39.         public String getNamespace() {
  40.             return QNAME.getNamespaceURI();
  41.         }

  42.         @Override
  43.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  44.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  45.             xml.closeEmptyElement();
  46.             return xml;
  47.         }
  48.     }

  49.     private abstract static class AbstractEnable implements Nonza {

  50.         /**
  51.          * Preferred maximum resumption time in seconds (optional).
  52.          */
  53.         protected int max = -1;

  54.         protected boolean resume = false;

  55.         protected void maybeAddResumeAttributeTo(XmlStringBuilder xml) {
  56.             if (resume) {
  57.                 // XEP 198 never mentions the case where resume='false', it's either set to true or
  58.                 // not set at all. We reflect this in this code part
  59.                 xml.attribute("resume", "true");
  60.             }
  61.         }

  62.         protected void maybeAddMaxAttributeTo(XmlStringBuilder xml) {
  63.             if (max > 0) {
  64.                 xml.attribute("max", Integer.toString(max));
  65.             }
  66.         }

  67.         public boolean isResumeSet() {
  68.             return resume;
  69.         }

  70.         /**
  71.          * Return the max resumption time in seconds.
  72.          * @return the max resumption time in seconds
  73.          */
  74.         public int getMaxResumptionTime() {
  75.             return max;
  76.         }

  77.         @Override
  78.         public final String getNamespace() {
  79.             return NAMESPACE;
  80.         }
  81.     }

  82.     public static class Enable extends AbstractEnable {
  83.         public static final String ELEMENT = "enable";

  84.         public static final Enable INSTANCE = new Enable();

  85.         private Enable() {
  86.         }

  87.         public Enable(boolean resume) {
  88.             this.resume = resume;
  89.         }

  90.         public Enable(boolean resume, int max) {
  91.             this(resume);
  92.             this.max = max;
  93.         }

  94.         @Override
  95.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  96.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  97.             maybeAddResumeAttributeTo(xml);
  98.             maybeAddMaxAttributeTo(xml);
  99.             xml.closeEmptyElement();
  100.             return xml;
  101.         }

  102.         @Override
  103.         public String getElementName() {
  104.             return ELEMENT;
  105.         }
  106.     }

  107.     /**
  108.      * A Stream Management 'enabled' element.
  109.      * <p>
  110.      * Here is a full example, all attributes besides 'xmlns' are optional.
  111.      * </p>
  112.      * <pre>
  113.      * {@code
  114.      * <enabled xmlns='urn:xmpp:sm:3'
  115.      *      id='some-long-sm-id'
  116.      *      location='[2001:41D0:1:A49b::1]:9222'
  117.      *      resume='true'/>
  118.      * }
  119.      * </pre>
  120.      */
  121.     public static class Enabled extends AbstractEnable {
  122.         public static final String ELEMENT = "enabled";

  123.         /**
  124.          * The stream id ("SM-ID")
  125.          */
  126.         private final String id;

  127.         /**
  128.          * The location where the server prefers reconnection.
  129.          */
  130.         private final String location;

  131.         public Enabled(String id, boolean resume) {
  132.             this(id, resume, null, -1);
  133.         }

  134.         public Enabled(String id, boolean resume, String location, int max) {
  135.             this.id = id;
  136.             this.resume = resume;
  137.             this.location = location;
  138.             this.max = max;
  139.         }

  140.         public String getId() {
  141.             return id;
  142.         }

  143.         public String getLocation() {
  144.             return location;
  145.         }

  146.         @Override
  147.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  148.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  149.             xml.optAttribute("id", id);
  150.             maybeAddResumeAttributeTo(xml);
  151.             xml.optAttribute("location", location);
  152.             maybeAddMaxAttributeTo(xml);
  153.             xml.closeEmptyElement();
  154.             return xml;
  155.         }

  156.         @Override
  157.         public String getElementName() {
  158.             return ELEMENT;
  159.         }
  160.     }

  161.     public static class Failed implements Nonza {
  162.         public static final String ELEMENT = "failed";

  163.         private final StanzaError.Condition condition;

  164.         private final List<StanzaErrorTextElement> textElements;


  165.         public Failed() {
  166.             this(null, null);
  167.         }

  168.         public Failed(StanzaError.Condition condition, List<StanzaErrorTextElement> textElements) {
  169.             this.condition = condition;
  170.             if (textElements == null) {
  171.                 this.textElements = Collections.emptyList();
  172.             } else {
  173.                 this.textElements = Collections.unmodifiableList(textElements);
  174.             }
  175.         }

  176.         public StanzaError.Condition getStanzaErrorCondition() {
  177.             return condition;
  178.         }

  179.         public List<StanzaErrorTextElement> getTextElements() {
  180.             return textElements;
  181.         }

  182.         @Override
  183.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  184.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  185.             if (condition == null && textElements.isEmpty()) {
  186.                 xml.closeEmptyElement();
  187.             } else {
  188.                 if (condition != null) {
  189.                     xml.rightAngleBracket();
  190.                     xml.append(condition.toString());
  191.                     xml.xmlnsAttribute(StanzaError.ERROR_CONDITION_AND_TEXT_NAMESPACE);
  192.                     xml.closeEmptyElement();
  193.                 }
  194.                 xml.append(textElements);
  195.                 xml.closeElement(ELEMENT);
  196.             }
  197.             return xml;
  198.         }

  199.         @Override
  200.         public String getNamespace() {
  201.             return NAMESPACE;
  202.         }

  203.         @Override
  204.         public String getElementName() {
  205.             return ELEMENT;
  206.         }

  207.     }

  208.     private abstract static class AbstractResume implements Nonza {

  209.         private final long handledCount;
  210.         private final String previd;

  211.         private AbstractResume(long handledCount, String previd) {
  212.             this.handledCount = handledCount;
  213.             this.previd = previd;
  214.         }

  215.         public long getHandledCount() {
  216.             return handledCount;
  217.         }

  218.         public String getPrevId() {
  219.             return previd;
  220.         }

  221.         @Override
  222.         public final String getNamespace() {
  223.             return NAMESPACE;
  224.         }

  225.         @Override
  226.         public final XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  227.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  228.             xml.attribute("h", Long.toString(handledCount));
  229.             xml.attribute("previd", previd);
  230.             xml.closeEmptyElement();
  231.             return xml;
  232.         }
  233.     }

  234.     public static class Resume extends AbstractResume {
  235.         public static final String ELEMENT = "resume";

  236.         public Resume(long handledCount, String previd) {
  237.             super(handledCount, previd);
  238.         }

  239.         @Override
  240.         public String getElementName() {
  241.             return ELEMENT;
  242.         }
  243.     }

  244.     public static class Resumed extends AbstractResume {
  245.         public static final String ELEMENT = "resumed";

  246.         public Resumed(long handledCount, String previd) {
  247.             super(handledCount, previd);
  248.         }

  249.         @Override
  250.         public String getElementName() {
  251.             return ELEMENT;
  252.         }
  253.     }

  254.     public static class AckAnswer implements Nonza {
  255.         public static final String ELEMENT = "a";

  256.         private final long handledCount;

  257.         public AckAnswer(long handledCount) {
  258.             this.handledCount = handledCount;
  259.         }

  260.         public long getHandledCount() {
  261.             return handledCount;
  262.         }

  263.         @Override
  264.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  265.             XmlStringBuilder xml = new XmlStringBuilder(this, enclosingNamespace);
  266.             xml.attribute("h", Long.toString(handledCount));
  267.             xml.closeEmptyElement();
  268.             return xml;
  269.         }

  270.         @Override
  271.         public String getNamespace() {
  272.             return NAMESPACE;
  273.         }

  274.         @Override
  275.         public String getElementName() {
  276.             return ELEMENT;
  277.         }
  278.     }

  279.     public static final class AckRequest implements Nonza {
  280.         public static final String ELEMENT = "r";
  281.         public static final AckRequest INSTANCE = new AckRequest();

  282.         private AckRequest() {
  283.         }

  284.         @Override
  285.         public CharSequence toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) {
  286.             return '<' + ELEMENT + " xmlns='" + NAMESPACE + "'/>";
  287.         }

  288.         @Override
  289.         public String getNamespace() {
  290.             return NAMESPACE;
  291.         }

  292.         @Override
  293.         public String getElementName() {
  294.             return ELEMENT;
  295.         }
  296.     }
  297. }