001/** 002 * 003 * Copyright 2003-2005 Jive Software. 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.smack.packet; 019 020import java.util.List; 021import java.util.Map; 022 023import org.jivesoftware.smack.util.StringUtils; 024import org.jivesoftware.smack.util.XmlStringBuilder; 025 026/** 027 * Represents a stream error packet. Stream errors are unrecoverable errors where the server 028 * will close the underlying TCP connection after the stream error was sent to the client. 029 * These is the list of stream errors as defined in the XMPP spec: 030 * 031 * <table border=1> 032 * <caption>Stream Errors</caption> 033 * <tr><td><b>Code</b></td><td><b>Description</b></td></tr> 034 * <tr><td> bad-format </td><td> the entity has sent XML that cannot be processed </td></tr> 035 * <tr><td> unsupported-encoding </td><td> the entity has sent a namespace prefix that is 036 * unsupported </td></tr> 037 * <tr><td> bad-namespace-prefix </td><td> Remote Server Timeout </td></tr> 038 * <tr><td> conflict </td><td> the server is closing the active stream for this entity 039 * because a new stream has been initiated that conflicts with the existing 040 * stream. </td></tr> 041 * <tr><td> connection-timeout </td><td> the entity has not generated any traffic over 042 * the stream for some period of time. </td></tr> 043 * <tr><td> host-gone </td><td> the value of the 'to' attribute provided by the initiating 044 * entity in the stream header corresponds to a hostname that is no longer hosted by 045 * the server. </td></tr> 046 * <tr><td> host-unknown </td><td> the value of the 'to' attribute provided by the 047 * initiating entity in the stream header does not correspond to a hostname that is 048 * hosted by the server. </td></tr> 049 * <tr><td> improper-addressing </td><td> a stanza sent between two servers lacks a 'to' 050 * or 'from' attribute </td></tr> 051 * <tr><td> internal-server-error </td><td> the server has experienced a 052 * misconfiguration. </td></tr> 053 * <tr><td> invalid-from </td><td> the JID or hostname provided in a 'from' address does 054 * not match an authorized JID. </td></tr> 055 * <tr><td> invalid-namespace </td><td> the streams namespace name is invalid. </td></tr> 056 * <tr><td> invalid-xml </td><td> the entity has sent invalid XML over the stream. </td></tr> 057 * <tr><td> not-authorized </td><td> the entity has attempted to send data before the 058 * stream has been authenticated </td></tr> 059 * <tr><td> policy-violation </td><td> the entity has violated some local service 060 * policy. </td></tr> 061 * <tr><td> remote-connection-failed </td><td> the server is unable to properly connect 062 * to a remote entity. </td></tr> 063 * <tr><td> resource-constraint </td><td> the server lacks the system resources necessary 064 * to service the stream. </td></tr> 065 * <tr><td> restricted-xml </td><td> the entity has attempted to send restricted XML 066 * features. </td></tr> 067 * <tr><td> see-other-host </td><td> the server will not provide service to the initiating 068 * entity but is redirecting traffic to another host. </td></tr> 069 * <tr><td> system-shutdown </td><td> the server is being shut down and all active streams 070 * are being closed. </td></tr> 071 * <tr><td> undefined-condition </td><td> the error condition is not one of those defined 072 * by the other conditions in this list. </td></tr> 073 * <tr><td> unsupported-encoding </td><td> the initiating entity has encoded the stream in 074 * an encoding that is not supported. </td></tr> 075 * <tr><td> unsupported-stanza-type </td><td> the initiating entity has sent a first-level 076 * child of the stream that is not supported. </td></tr> 077 * <tr><td> unsupported-version </td><td> the value of the 'version' attribute provided by 078 * the initiating entity in the stream header specifies a version of XMPP that is not 079 * supported. </td></tr> 080 * <tr><td> not-well-formed </td><td> the initiating entity has sent XML that is not 081 * well-formed. </td></tr> 082 * </table> 083 * <p> 084 * Stream error syntax: 085 * <pre> 086 * {@code 087 * <stream:error> 088 * <defined-condition xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> 089 * [<text xmlns='urn:ietf:params:xml:ns:xmpp-streams' 090 * xml:lang='langcode'> 091 * OPTIONAL descriptive text 092 * </text>] 093 * [OPTIONAL application-specific condition element] 094 * </stream:error> 095 * } 096 * </pre> 097 * 098 * @author Gaston Dombiak 099 */ 100public class StreamError extends AbstractError implements Nonza { 101 102 public static final String ELEMENT = "stream:error"; 103 public static final String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-streams"; 104 105 private final Condition condition; 106 private final String conditionText; 107 108 public StreamError(Condition condition, String conditionText, Map<String, String> descriptiveTexts, List<XmlElement> extensions) { 109 super(descriptiveTexts, extensions); 110 // Some implementations may send the condition as non-empty element containing the empty string, that is 111 // <condition xmlns='foo'></condition>, in this case the parser may calls this constructor with the empty string 112 // as conditionText, therefore reset it to null if it's the empty string 113 if (StringUtils.isNullOrEmpty(conditionText)) { 114 conditionText = null; 115 } 116 if (conditionText != null) { 117 switch (condition) { 118 case see_other_host: 119 break; 120 default: 121 throw new IllegalArgumentException("The given condition '" + condition 122 + "' can not contain a conditionText"); 123 } 124 } 125 this.condition = condition; 126 this.conditionText = conditionText; 127 } 128 129 public Condition getCondition() { 130 return condition; 131 } 132 133 public String getConditionText() { 134 return conditionText; 135 } 136 137 @Override 138 public String toString() { 139 return toXML().toString(); 140 } 141 142 @Override 143 public XmlStringBuilder toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 144 XmlStringBuilder xml = new XmlStringBuilder(); 145 xml.openElement(ELEMENT); 146 xml.halfOpenElement(condition.toString()).xmlnsAttribute(NAMESPACE).closeEmptyElement(); 147 addDescriptiveTextsAndExtensions(xml); 148 xml.closeElement(ELEMENT); 149 return xml; 150 } 151 152 /** 153 * The defined stream error conditions, see RFC 6120 ยง 4.9.3. 154 * 155 */ 156 public enum Condition { 157 bad_format, 158 bad_namespace_prefix, 159 conflict, 160 connection_timeout, 161 host_gone, 162 host_unknown, 163 improper_addressing, 164 internal_server_error, 165 invalid_from, 166 invalid_namespace, 167 invalid_xml, 168 not_authorized, 169 not_well_formed, 170 policy_violation, 171 remote_connection_failed, 172 reset, 173 resource_constraint, 174 restricted_xml, 175 see_other_host, 176 system_shutdown, 177 undefined_condition, 178 unsupported_encoding, 179 unsupported_feature, 180 unsupported_stanza_type, 181 unsupported_version; 182 183 @Override 184 public String toString() { 185 return this.name().replace('_', '-'); 186 } 187 188 public static Condition fromString(String string) { 189 // Backwards compatibility for older implementations still using RFC 3920. RFC 6120 190 // changed 'xml-not-well-formed' to 'not-well-formed'. 191 if ("xml-not-well-formed".equals(string)) { 192 string = "not-well-formed"; 193 } 194 string = string.replace('-', '_'); 195 Condition condition = null; 196 try { 197 condition = Condition.valueOf(string); 198 } catch (Exception e) { 199 throw new IllegalStateException("Could not transform string '" + string 200 + "' to XMPPErrorCondition", e); 201 } 202 return condition; 203 } 204 } 205 206 @Override 207 public String getNamespace() { 208 return NAMESPACE; 209 } 210 211 @Override 212 public String getElementName() { 213 return ELEMENT; 214 } 215}