001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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.apache.juneau.http.classic.response; 018 019import static org.apache.juneau.commons.utils.Shorts.*; 020import static org.apache.juneau.http.classic.response.TooManyRequests.*; 021 022import java.util.*; 023 024import org.apache.http.*; 025import org.apache.http.Header; 026import org.apache.juneau.commons.*; 027import org.apache.juneau.http.*; 028import org.apache.juneau.http.classic.*; 029import org.apache.juneau.http.classic.header.*; 030 031/** 032 * Exception representing an HTTP 429 (Too Many Requests). 033 * 034 * <p> 035 * The user has sent too many requests in a given amount of time. 036 * <br>Intended for use with rate-limiting schemes. 037 * 038 * <h5 class='section'>See Also:</h5><ul> 039 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommon">juneau-rest-common</a> 040 * </ul> 041 * 042 * @serial exclude 043 */ 044@Response 045@StatusCode(STATUS_CODE) 046@Schema(description = REASON_PHRASE) 047@SuppressWarnings({ 048 "java:S110" // Inheritance depth acceptable for HTTP exception hierarchy 049}) 050public class TooManyRequests extends BasicHttpException { 051 private static final long serialVersionUID = 1L; 052 053 /** HTTP status code */ 054 public static final int STATUS_CODE = 429; 055 056 /** Reason phrase */ 057 public static final String REASON_PHRASE = "Too Many Requests"; 058 059 /** Default status line */ 060 private static final BasicStatusLine STATUS_LINE = BasicStatusLine.create(STATUS_CODE, REASON_PHRASE); 061 062 /** Reusable unmodifiable instance */ 063 public static final TooManyRequests INSTANCE = new TooManyRequests().unmodifiable(); 064 065 /** 066 * Constructor. 067 */ 068 public TooManyRequests() { 069 this((Throwable)null, REASON_PHRASE); 070 } 071 072 /** 073 * Constructor. 074 * 075 * <p> 076 * This is the constructor used when parsing an HTTP response. 077 * 078 * @param response The HTTP response to copy from. Must not be <jk>null</jk>. 079 * @throws IllegalArgumentException If HTTP response status code does not match what was expected. 080 */ 081 public TooManyRequests(HttpResponse response) { 082 super(requireStatus(response, STATUS_CODE)); 083 } 084 085 /** 086 * Constructor. 087 * 088 * @param msg The message. Can be <jk>null</jk>, in which case the reason phrase is used as the message. 089 * @param args Optional {@link String#format(String, Object...) String.format}-style arguments in the message. 090 */ 091 public TooManyRequests(String msg, Object...args) { 092 this((Throwable)null, msg, args); 093 } 094 095 /** 096 * Constructor. 097 * 098 * @param cause The cause. Can be <jk>null</jk>, in which case the reason phrase is used as the message and no cause is chained. 099 */ 100 public TooManyRequests(Throwable cause) { 101 this(cause, cause == null ? REASON_PHRASE : cause.getMessage()); 102 } 103 104 /** 105 * Constructor. 106 * 107 * @param cause The caused-by exception. Can be <jk>null</jk> (no cause is chained). 108 * @param msg The message. Can be <jk>null</jk>, in which case the cause's message is used, or the reason phrase if the cause is also <jk>null</jk> or has no message. 109 * @param args The message arguments. 110 */ 111 public TooManyRequests(Throwable cause, String msg, Object...args) { 112 super(STATUS_CODE, cause, msg, args); 113 setStatusLine(STATUS_LINE.copy()); 114 } 115 116 /** 117 * Copy constructor. 118 * 119 * @param copyFrom The bean to copy. Must not be <jk>null</jk>. 120 */ 121 protected TooManyRequests(TooManyRequests copyFrom) { 122 super(copyFrom); 123 } 124 125 /** 126 * Creates a modifiable copy of this bean. 127 * 128 * @return A new modifiable bean. 129 */ 130 public TooManyRequests copy() { 131 return new TooManyRequests(this); 132 } 133 134 @Override /* Overridden from BasicHttpException */ 135 public TooManyRequests setContent(HttpEntity value) { 136 super.setContent(value); 137 return this; 138 } 139 140 @Override /* Overridden from BasicHttpException */ 141 public TooManyRequests setContent(String value) { 142 super.setContent(value); 143 return this; 144 } 145 146 @Override /* Overridden from BasicHttpException */ 147 public TooManyRequests setHeader2(String name, Object value) { 148 super.setHeader2(name, value); 149 return this; 150 } 151 152 @Override /* Overridden from BasicHttpException */ 153 public TooManyRequests setHeaders(HeaderList value) { 154 super.setHeaders(value); 155 return this; 156 } 157 158 @Override /* Overridden from BasicHttpException */ 159 public TooManyRequests setHeaders(List<Header> values) { 160 super.setHeaders(values); 161 return this; 162 } 163 164 @Override /* Overridden from BasicHttpException */ 165 public TooManyRequests setHeaders2(Header...values) { 166 super.setHeaders2(values); 167 return this; 168 } 169 170 @Override /* Overridden from BasicHttpException */ 171 public TooManyRequests setLocale2(Locale value) { 172 super.setLocale2(value); 173 return this; 174 } 175 176 @Override /* Overridden from BasicRuntimeException */ 177 public TooManyRequests setMessage(String message, Object...args) { 178 super.setMessage(message, args); 179 return this; 180 } 181 182 @Override /* Overridden from BasicHttpException */ 183 public TooManyRequests setProtocolVersion(ProtocolVersion value) { 184 super.setProtocolVersion(value); 185 return this; 186 } 187 188 @Override /* Overridden from BasicHttpException */ 189 public TooManyRequests setReasonPhrase2(String value) { 190 super.setReasonPhrase2(value); 191 return this; 192 } 193 194 @Override /* Overridden from BasicHttpException */ 195 public TooManyRequests setReasonPhraseCatalog(ReasonPhraseCatalog value) { 196 super.setReasonPhraseCatalog(value); 197 return this; 198 } 199 200 @Override /* Overridden from BasicHttpException */ 201 public TooManyRequests setStatusCode2(int code) throws IllegalStateException { 202 super.setStatusCode2(code); 203 return this; 204 } 205 206 @Override /* Overridden from BasicHttpException */ 207 public TooManyRequests setStatusLine(BasicStatusLine value) { 208 super.setStatusLine(value); 209 return this; 210 } 211 212 @Override /* Overridden from BasicHttpException */ 213 public TooManyRequests unmodifiable() { 214 return this instanceof UnmodifiableBean ? this : new Unmodifiable(this); 215 } 216 217 /** 218 * Unmodifiable point-in-time snapshot of the enclosing {@link TooManyRequests} exception. 219 * 220 * <p> 221 * Its only behavioral override is {@link #modify(Runnable)}, which throws — because all mutation is funneled through 222 * {@code modify(...)}, this single override freezes the entire mutation surface. 223 */ 224 public static class Unmodifiable extends TooManyRequests implements UnmodifiableBean { 225 226 private static final long serialVersionUID = 1L; 227 228 /** 229 * Constructor. 230 * 231 * @param copyFrom The exception to snapshot. Must not be <jk>null</jk>. 232 */ 233 @SuppressWarnings({ 234 "java:S1699" // Paradigm intentionally calls the overridable freeze() from the ctor to deep-freeze sub-beans. 235 }) 236 protected Unmodifiable(TooManyRequests copyFrom) { 237 super(copyFrom); 238 freeze(); 239 } 240 241 @Override /* Overridden from BasicHttpException */ 242 protected BasicHttpException modify(Runnable mutation) { 243 throw uoex("Bean is unmodifiable."); 244 } 245 } 246}