View Javadoc
1   /*
2    * Copyright 2019-2022 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.bremersee.exception;
18  
19  import static java.util.Objects.isNull;
20  
21  import java.io.Serial;
22  import lombok.EqualsAndHashCode;
23  import lombok.Getter;
24  
25  /**
26   * General service exception with http status code and error code.
27   *
28   * @author Christian Bremer
29   */
30  @EqualsAndHashCode(callSuper = true)
31  public class ServiceException extends RuntimeException
32      implements ErrorCodeAware, HttpStatusAware {
33  
34    @Serial
35    private static final long serialVersionUID = 2L;
36  
37    /**
38     * Default error code for an 'already exists exception'.
39     */
40    public static final String ERROR_CODE_ALREADY_EXISTS = "COMMON:ALREADY_EXISTS";
41  
42    /**
43     * The http status.
44     */
45    private final int httpStatus;
46  
47    /**
48     * The error code.
49     */
50    @Getter
51    private final String errorCode;
52  
53    /**
54     * Instantiates a new service exception.
55     */
56    protected ServiceException() {
57      super();
58      this.httpStatus = 0;
59      this.errorCode = null;
60    }
61  
62    /**
63     * Instantiates a new service exception.
64     *
65     * @param httpStatus the http status
66     * @param errorCode the error code
67     */
68    protected ServiceException(int httpStatus, String errorCode) {
69      super();
70      this.httpStatus = httpStatus;
71      this.errorCode = errorCode;
72    }
73  
74    /**
75     * Instantiates a new service exception.
76     *
77     * @param httpStatus the http status
78     * @param errorCode the error code
79     * @param reason the reason
80     */
81    protected ServiceException(int httpStatus, String errorCode, String reason) {
82      super(reason);
83      this.httpStatus = httpStatus;
84      this.errorCode = errorCode;
85    }
86  
87    /**
88     * Instantiates a new service exception.
89     *
90     * @param httpStatus the http status
91     * @param errorCode the error code
92     * @param cause the cause
93     */
94    protected ServiceException(int httpStatus, String errorCode, Throwable cause) {
95      super(cause);
96      this.httpStatus = httpStatus;
97      this.errorCode = errorCode;
98    }
99  
100   /**
101    * Instantiates a new service exception.
102    *
103    * @param httpStatus the http status
104    * @param errorCode the error code
105    * @param reason the reason
106    * @param cause the cause
107    */
108   protected ServiceException(
109       int httpStatus,
110       String errorCode,
111       String reason,
112       Throwable cause) {
113     super(reason, cause);
114     this.httpStatus = httpStatus;
115     this.errorCode = errorCode;
116   }
117 
118   /**
119    * Get the http status.
120    *
121    * @return the http status
122    */
123   @Override
124   public int status() {
125     return httpStatus;
126   }
127 
128   /**
129    * Internal server error service exception.
130    *
131    * @return the service exception
132    */
133   public static ServiceException internalServerError() {
134     return internalServerError(null);
135   }
136 
137   /**
138    * Internal server error service exception.
139    *
140    * @param reason the reason
141    * @return the service exception
142    */
143   public static ServiceException internalServerError(String reason) {
144     return internalServerError(reason, (String) null);
145   }
146 
147   /**
148    * Internal server error service exception.
149    *
150    * @param reason the reason
151    * @param cause the cause
152    * @return the service exception
153    */
154   public static ServiceException internalServerError(String reason, Throwable cause) {
155     return internalServerError(reason, null, cause);
156   }
157 
158   /**
159    * Internal server error service exception.
160    *
161    * @param reason the reason
162    * @param errorCode the error code
163    * @return the service exception
164    */
165   public static ServiceException internalServerError(String reason, String errorCode) {
166     return internalServerError(reason, errorCode, null);
167   }
168 
169   /**
170    * Internal server error service exception.
171    *
172    * @param reason the reason
173    * @param errorCode the error code
174    * @param cause the cause
175    * @return the service exception
176    */
177   public static ServiceException internalServerError(
178       String reason,
179       String errorCode,
180       Throwable cause) {
181     return ServiceException.builder()
182         .httpStatus(500)
183         .reason(reason)
184         .errorCode(errorCode)
185         .cause(cause)
186         .build();
187   }
188 
189 
190   /**
191    * Bad request service exception.
192    *
193    * @return the service exception
194    */
195   public static ServiceException badRequest() {
196     return badRequest(null);
197   }
198 
199   /**
200    * Bad request service exception.
201    *
202    * @param reason the reason
203    * @return the service exception
204    */
205   public static ServiceException badRequest(String reason) {
206     return badRequest(reason, (String) null);
207   }
208 
209   /**
210    * Bad request service exception.
211    *
212    * @param reason the reason
213    * @param cause the cause
214    * @return the service exception
215    */
216   public static ServiceException badRequest(String reason, Throwable cause) {
217     return badRequest(reason, null, cause);
218   }
219 
220   /**
221    * Bad request service exception.
222    *
223    * @param reason the reason
224    * @param errorCode the error code
225    * @return the service exception
226    */
227   public static ServiceException badRequest(String reason, String errorCode) {
228     return badRequest(reason, errorCode, null);
229   }
230 
231   /**
232    * Bad request service exception.
233    *
234    * @param reason the reason
235    * @param errorCode the error code
236    * @param cause the cause
237    * @return the service exception
238    */
239   public static ServiceException badRequest(
240       String reason,
241       String errorCode,
242       Throwable cause) {
243     return ServiceException.builder()
244         .httpStatus(400)
245         .reason(reason)
246         .errorCode(errorCode)
247         .cause(cause)
248         .build();
249   }
250 
251   /**
252    * Not found service exception.
253    *
254    * @return the service exception
255    */
256   public static ServiceException notFound() {
257     return new ServiceException(404, null);
258   }
259 
260   /**
261    * Not found service exception.
262    *
263    * @param entityName the entity name
264    * @return the service exception
265    */
266   public static ServiceException notFound(Object entityName) {
267     return notFound("Entity", entityName);
268   }
269 
270   /**
271    * Not found service exception.
272    *
273    * @param entityType the entity type
274    * @param entityName the entity name
275    * @return the service exception
276    */
277   public static ServiceException notFound(String entityType, Object entityName) {
278     return notFoundWithErrorCode(entityType, entityName, null);
279   }
280 
281   /**
282    * Not found with error code service exception.
283    *
284    * @param entityName the entity name
285    * @param errorCode the error code
286    * @return the service exception
287    */
288   public static ServiceException notFoundWithErrorCode(
289       Object entityName,
290       String errorCode) {
291     return notFoundWithErrorCode("Entity", entityName, errorCode);
292   }
293 
294   /**
295    * Not found with error code service exception.
296    *
297    * @param entityType the entity type
298    * @param entityName the entity name
299    * @param errorCode the error code
300    * @return the service exception
301    */
302   public static ServiceException notFoundWithErrorCode(
303       String entityType,
304       Object entityName,
305       String errorCode) {
306     return new ServiceException(404, errorCode,
307         entityType + " with identifier [" + entityName + "] was not found.");
308   }
309 
310   /**
311    * Already exists service exception.
312    *
313    * @return the service exception
314    */
315   public static ServiceException alreadyExists() {
316     return new ServiceException(409, null);
317   }
318 
319   /**
320    * Already exists service exception.
321    *
322    * @param entityName the entity name
323    * @return the service exception
324    */
325   public static ServiceException alreadyExists(
326       Object entityName) {
327     return alreadyExistsWithErrorCode("Entity", entityName, null);
328   }
329 
330   /**
331    * Already exists service exception.
332    *
333    * @param entityType the entity type
334    * @param entityName the entity name
335    * @return the service exception
336    */
337   public static ServiceException alreadyExists(
338       String entityType,
339       Object entityName) {
340     return alreadyExistsWithErrorCode(entityType, entityName, null);
341   }
342 
343   /**
344    * Already exists with error code service exception.
345    *
346    * @param entityName the entity name
347    * @param errorCode the error code
348    * @return the service exception
349    */
350   public static ServiceException alreadyExistsWithErrorCode(
351       Object entityName,
352       String errorCode) {
353     return alreadyExistsWithErrorCode("Entity", entityName, errorCode);
354   }
355 
356   /**
357    * Already exists with error code service exception.
358    *
359    * @param entityType the entity type
360    * @param entityName the entity name
361    * @param errorCode the error code
362    * @return the service exception
363    */
364   public static ServiceException alreadyExistsWithErrorCode(
365       String entityType,
366       Object entityName,
367       String errorCode) {
368     return new ServiceException(
369         409,
370         isNull(errorCode) || errorCode.isBlank() ? ERROR_CODE_ALREADY_EXISTS : errorCode,
371         entityType + " with identifier [" + entityName + "] already exists.");
372   }
373 
374   /**
375    * Forbidden service exception.
376    *
377    * @return the service exception
378    */
379   public static ServiceException forbidden() {
380     return new ServiceException(403, null);
381   }
382 
383   /**
384    * Forbidden service exception.
385    *
386    * @param entityName the entity name
387    * @return the service exception
388    */
389   public static ServiceException forbidden(Object entityName) {
390     return forbiddenWithErrorCode(entityName, null);
391   }
392 
393   /**
394    * Forbidden service exception.
395    *
396    * @param entityType the entity type
397    * @param entityName the entity name
398    * @return the service exception
399    */
400   public static ServiceException forbidden(String entityType, Object entityName) {
401     return forbiddenWithErrorCode(entityType, entityName, null);
402   }
403 
404   /**
405    * Forbidden with error code service exception.
406    *
407    * @param errorCode the error code
408    * @return the service exception
409    */
410   public static ServiceException forbiddenWithErrorCode(String errorCode) {
411     return new ServiceException(403, errorCode);
412   }
413 
414   /**
415    * Forbidden with error code service exception.
416    *
417    * @param entityName the entity name
418    * @param errorCode the error code
419    * @return the service exception
420    */
421   public static ServiceException forbiddenWithErrorCode(Object entityName, String errorCode) {
422     return new ServiceException(403, errorCode,
423         "Access to entity with identifier [" + entityName + "] is forbidden.");
424   }
425 
426   /**
427    * Forbidden with error code service exception.
428    *
429    * @param entityType the entity type
430    * @param entityName the entity name
431    * @param errorCode the error code
432    * @return the service exception
433    */
434   public static ServiceException forbiddenWithErrorCode(
435       String entityType,
436       Object entityName,
437       String errorCode) {
438     return new ServiceException(403, errorCode,
439         "Access to [" + entityType + "] with identifier [" + entityName + "] is forbidden.");
440   }
441 
442   /**
443    * Creates new exception builder.
444    *
445    * @return the builder
446    */
447   public static ServiceExceptionBuilder<? extends ServiceException> builder() {
448 
449     return new AbstractServiceExceptionBuilder<>() {
450 
451       @Serial
452       private static final long serialVersionUID = 2L;
453 
454       @Override
455       protected ServiceException buildWith(
456           int httpStatus,
457           String errorCode,
458           String reason,
459           Throwable cause) {
460         return new ServiceException(httpStatus, errorCode, reason, cause);
461       }
462     };
463   }
464 
465 }