AbstractError.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.packet;

  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.HashMap;
  21. import java.util.List;
  22. import java.util.Locale;
  23. import java.util.Map;

  24. import org.jivesoftware.smack.util.ExceptionUtil;
  25. import org.jivesoftware.smack.util.Objects;
  26. import org.jivesoftware.smack.util.PacketUtil;
  27. import org.jivesoftware.smack.util.XmlStringBuilder;

  28. public class AbstractError {

  29.     protected final String textNamespace;
  30.     protected final Map<String, String> descriptiveTexts;
  31.     protected final List<XmlElement> extensions;


  32.     protected AbstractError(Map<String, String> descriptiveTexts) {
  33.         this(descriptiveTexts, null);
  34.     }

  35.     protected AbstractError(Map<String, String> descriptiveTexts, List<XmlElement> extensions) {
  36.         this(descriptiveTexts, null, extensions);
  37.     }

  38.     protected AbstractError(Map<String, String> descriptiveTexts, String textNamespace, List<XmlElement> extensions) {
  39.         if (descriptiveTexts != null) {
  40.             this.descriptiveTexts = descriptiveTexts;
  41.         } else {
  42.             this.descriptiveTexts = Collections.emptyMap();
  43.         }
  44.         this.textNamespace = textNamespace;
  45.         if (extensions != null) {
  46.             this.extensions = extensions;
  47.         } else {
  48.             this.extensions = Collections.emptyList();
  49.         }
  50.     }

  51.     /**
  52.      * Get the descriptive text of this SASLFailure.
  53.      * <p>
  54.      * Returns the descriptive text of this SASLFailure in the system default language if possible. May return null.
  55.      * </p>
  56.      *
  57.      * @return the descriptive text or null.
  58.      */
  59.     public String getDescriptiveText() {
  60.         if (descriptiveTexts.isEmpty())
  61.             return null;
  62.         // attempt to obtain the text in the user's locale, the English text, or the "" default
  63.         Locale l = Locale.getDefault();
  64.         String[] tags = new String[] {
  65.                 l.getLanguage() + "-" + l.getCountry() + "-" + l.getVariant(),
  66.                 l.getLanguage() + "-" + l.getCountry(),
  67.                 l.getLanguage(),
  68.                 "en",
  69.                 ""
  70.         };
  71.         for (String tag : tags) {
  72.             String descriptiveText = getDescriptiveText(tag);
  73.             if (descriptiveText != null)
  74.                 return descriptiveText;
  75.         }
  76.         return descriptiveTexts.values().iterator().next();
  77.     }

  78.     /**
  79.      * Get the descriptive test of this SASLFailure.
  80.      * <p>
  81.      * Returns the descriptive text of this SASLFailure in the given language. May return null if not available.
  82.      * </p>
  83.      *
  84.      * @param xmllang the language.
  85.      * @return the descriptive text or null.
  86.      */
  87.     public String getDescriptiveText(String xmllang) {
  88.         Objects.requireNonNull(xmllang, "xmllang must not be null");
  89.         return descriptiveTexts.get(xmllang);
  90.     }

  91.     /**
  92.      * Returns the first stanza extension that matches the specified element name and
  93.      * namespace, or <code>null</code> if it doesn't exist.
  94.      *
  95.      * @param elementName the XML element name of the stanza extension.
  96.      * @param namespace the XML element namespace of the stanza extension.
  97.      * @param <PE> type of the ExtensionElement.
  98.      * @return the extension, or <code>null</code> if it doesn't exist.
  99.      */
  100.     public <PE extends XmlElement> PE getExtension(String elementName, String namespace) {
  101.         return PacketUtil.extensionElementFrom(extensions, elementName, namespace);
  102.     }

  103.     protected void addDescriptiveTextsAndExtensions(XmlStringBuilder xml) {
  104.         for (Map.Entry<String, String> entry : descriptiveTexts.entrySet()) {
  105.             String xmllang = entry.getKey();
  106.             String text = entry.getValue();
  107.             xml.halfOpenElement("text").xmlnsAttribute(textNamespace)
  108.                     .optXmlLangAttribute(xmllang)
  109.                     .rightAngleBracket();
  110.             xml.escape(text);
  111.             xml.closeElement("text");
  112.         }
  113.         xml.append(extensions);
  114.     }

  115.     public abstract static class Builder<B extends Builder<B>> {
  116.         protected String textNamespace;
  117.         protected Map<String, String> descriptiveTexts;
  118.         protected List<XmlElement> extensions;

  119.         public B setDescriptiveTexts(Map<String, String> descriptiveTexts) {
  120.             if (descriptiveTexts == null) {
  121.                 this.descriptiveTexts = null;
  122.                 return getThis();
  123.             }
  124.             for (String key : descriptiveTexts.keySet()) {
  125.                 if (key == null) {
  126.                     throw new IllegalArgumentException("descriptiveTexts cannot contain null key");
  127.                 }
  128.             }
  129.             if (this.descriptiveTexts == null) {
  130.                 this.descriptiveTexts = descriptiveTexts;
  131.             }
  132.             else {
  133.                 this.descriptiveTexts.putAll(descriptiveTexts);
  134.             }
  135.             return getThis();
  136.         }

  137.         public B setDescriptiveEnText(String descriptiveEnText) {
  138.             if (descriptiveTexts == null) {
  139.                 descriptiveTexts = new HashMap<>();
  140.             }
  141.             descriptiveTexts.put("en", descriptiveEnText);
  142.             return getThis();
  143.         }

  144.         public B setDescriptiveEnText(String descriptiveEnText, Exception exception) {
  145.             StringBuilder sb = new StringBuilder(512);
  146.             sb.append(descriptiveEnText)
  147.                 .append('\n');

  148.             String stacktrace = ExceptionUtil.getStackTrace(exception);
  149.             sb.append(stacktrace);

  150.             return setDescriptiveEnText(sb.toString());
  151.         }

  152.         public B setTextNamespace(String textNamespace) {
  153.             this.textNamespace = textNamespace;
  154.             return getThis();
  155.         }

  156.         public B setExtensions(List<XmlElement> extensions) {
  157.             if (this.extensions == null) {
  158.                 this.extensions = extensions;
  159.             }
  160.             else {
  161.                 this.extensions.addAll(extensions);
  162.             }
  163.             return getThis();
  164.         }

  165.         public B addExtension(XmlElement extension) {
  166.             if (extensions == null) {
  167.                 extensions = new ArrayList<>();
  168.             }
  169.             extensions.add(extension);
  170.             return getThis();
  171.         }

  172.         protected abstract B getThis();
  173.     }
  174. }