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