001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau;
014
015import static org.apache.juneau.common.internal.StringUtils.*;
016
017import java.text.*;
018
019import org.apache.juneau.common.internal.*;
020import org.apache.juneau.internal.*;
021
022/**
023 * Subclass of runtime exceptions that take in a message and zero or more arguments.
024 *
025 * <h5 class='section'>See Also:</h5><ul>
026
027 * </ul>
028 *
029 * @serial exclude
030 */
031@FluentSetters
032public class BasicRuntimeException extends RuntimeException {
033
034   //-----------------------------------------------------------------------------------------------------------------
035   // Static
036   //-----------------------------------------------------------------------------------------------------------------
037
038   private static final long serialVersionUID = 1L;
039
040   //-----------------------------------------------------------------------------------------------------------------
041   // Instance
042   //-----------------------------------------------------------------------------------------------------------------
043
044   boolean unmodifiable;
045   String message;
046
047   /**
048    * Constructor.
049    *
050    * @param cause The cause of this exception.
051    * @param message The {@link MessageFormat}-style message.
052    * @param args Optional {@link MessageFormat}-style arguments.
053    */
054   public BasicRuntimeException(Throwable cause, String message, Object...args) {
055      super(format(message, args), cause);
056   }
057
058   /**
059    * Constructor.
060    *
061    * @param message The {@link MessageFormat}-style message.
062    * @param args Optional {@link MessageFormat}-style arguments.
063    */
064   public BasicRuntimeException(String message, Object...args) {
065      super(format(message, args));
066   }
067
068   /**
069    * Constructor.
070    *
071    * @param cause The cause of this exception.
072    */
073   public BasicRuntimeException(Throwable cause) {
074      super(cause);
075   }
076
077   //-----------------------------------------------------------------------------------------------------------------
078   // Properties
079   //-----------------------------------------------------------------------------------------------------------------
080
081   /**
082    * Specifies whether this bean should be unmodifiable.
083    * <p>
084    * When enabled, attempting to set any properties on this bean will cause an {@link UnsupportedOperationException}.
085    *
086    * @return This object.
087    */
088   @FluentSetter
089   protected BasicRuntimeException setUnmodifiable() {
090      unmodifiable = true;
091      return this;
092   }
093
094   /**
095    * Returns <jk>true</jk> if this bean is unmodifiable.
096    *
097    * @return <jk>true</jk> if this bean is unmodifiable.
098    */
099   public boolean isUnmodifiable() {
100      return unmodifiable;
101   }
102
103   /**
104    * Throws an {@link UnsupportedOperationException} if the unmodifiable flag is set on this bean.
105    */
106   protected final void assertModifiable() {
107      if (unmodifiable)
108         throw new UnsupportedOperationException("Bean is read-only");
109   }
110
111   /**
112    * Same as {@link #getCause()} but searches the throwable chain for an exception of the specified type.
113    *
114    * @param c The throwable type to search for.
115    * @param <T> The throwable type to search for.
116    * @return The exception, or <jk>null</jk> if not found.
117    */
118   public <T extends Throwable> T getCause(Class<T> c) {
119      return ThrowableUtils.getCause(c, this);
120   }
121
122   /**
123    * Sets the detail message on this exception.
124    *
125    * @param message The message.
126    * @param args The message args.
127    * @return This object.
128    */
129   @FluentSetter
130   public BasicRuntimeException setMessage(String message, Object...args) {
131      assertModifiable();
132      this.message = format(message, args);
133      return this;
134   }
135
136   @Override /* Throwable */
137   public String getMessage() {
138      if (message != null)
139         return message;
140      String m = super.getMessage();
141      if (m == null && getCause() != null)
142         m = getCause().getMessage();
143      return m;
144   }
145
146   @Override /* Throwable */
147   public synchronized Throwable fillInStackTrace() {
148      assertModifiable();
149      return super.fillInStackTrace();
150   }
151
152   @Override /* Throwable */
153   public synchronized Throwable initCause(Throwable cause) {
154      assertModifiable();
155      return super.initCause(cause);
156   }
157
158   @Override /* Throwable */
159   public void setStackTrace(StackTraceElement[] stackTrace) {
160      assertModifiable();
161      super.setStackTrace(stackTrace);
162   }
163
164   /**
165    * Returns the caused-by exception if there is one.
166    *
167    * @return The caused-by exception if there is one, or this exception if there isn't.
168    */
169   public Throwable unwrap() {
170      Throwable t = getCause();
171      return t == null ? this : t;
172   }
173
174   // <FluentSetters>
175
176   // </FluentSetters>
177}