View Javadoc
1   package org.apache.onami.persist;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.PrintStream;
23  import java.io.PrintWriter;
24  import java.util.ArrayList;
25  import java.util.List;
26  
27  import static org.apache.onami.persist.Preconditions.checkNotNull;
28  
29  /**
30   * Exception holding an aggregation of multiple exceptions which were collected.
31   */
32  class AggregatedException
33      extends RuntimeException
34  {
35  
36      private static final long serialVersionUID = 1L;
37  
38      /**
39       * Builder for AggregatedException
40       */
41      static class Builder
42      {
43  
44          /**
45           * list of causes for the aggregated exception.
46           */
47          private List<Throwable> causes = new ArrayList<Throwable>();
48  
49          /**
50           * Adds an exception to the list of aggregated exceptions.
51           *
52           * @param cause the exception to add
53           */
54          void add( Throwable cause )
55          {
56              causes.add( checkNotNull( cause, "cause is mandatory!" ) );
57          }
58  
59          /**
60           * Throws a runtime exception if the builder has causes.
61           *
62           * @param msg the message of the aggregated exception.
63           */
64          void throwRuntimeExceptionIfHasCauses( String msg )
65          {
66              try
67              {
68                  if ( !causes.isEmpty() )
69                  {
70                      throw getRuntimeException( msg );
71                  }
72              }
73              finally
74              {
75                  causes = null;
76              }
77          }
78  
79          /**
80           * Converts the collected causes into a runtime exception
81           *
82           * @param msg the message of the aggregated exception.
83           * @return the exception to throw
84           */
85          private RuntimeException getRuntimeException( String msg )
86          {
87              if ( causes.size() == 1 )
88              {
89                  final Throwable cause = causes.get( 0 );
90                  if ( cause instanceof RuntimeException )
91                  {
92                      return (RuntimeException) cause;
93                  }
94              }
95              return new AggregatedException( msg, causes.toArray( new Throwable[causes.size()] ) );
96          }
97      }
98  
99      /**
100      * all the underlying causes for this aggregated exception.
101      */
102     private final Throwable[] causes;
103 
104     /**
105      * number of causes for this aggregated exceptions.
106      */
107     private final int numCauses;
108 
109     /**
110      * Constructor.
111      *
112      * @param message the message
113      * @param causes  all the causes
114      */
115     private AggregatedException( String message, Throwable[] causes )
116     {
117         super( message );
118         this.causes = causes;
119         this.numCauses = this.causes.length;
120     }
121 
122     /**
123      * @return the causes which lead to this exception
124      */
125     public Throwable[] getCauses()
126     {
127         return causes.clone();
128     }
129 
130     /**
131      * @return the number of causes collected into this exception
132      */
133     public int getNumCauses()
134     {
135         return numCauses;
136     }
137 
138     /**
139      * {@inheritDoc}
140      */
141     @Override
142     public void printStackTrace( PrintStream s )
143     {
144         synchronized ( s )
145         {
146 
147             s.println( this );
148             StackTraceElement[] trace = getStackTrace();
149             for ( final StackTraceElement aTrace : trace )
150             {
151                 s.println( "\tat " + aTrace );
152             }
153 
154             for ( int i = 0; i < numCauses; i++ )
155             {
156                 s.println( "Cause " + ( i + 1 ) + ":" );
157                 causes[i].printStackTrace( s );
158             }
159         }
160     }
161 
162     /**
163      * {@inheritDoc}
164      */
165     @Override
166     public void printStackTrace( PrintWriter s )
167     {
168         synchronized ( s )
169         {
170 
171             s.println( this );
172             StackTraceElement[] trace = getStackTrace();
173             for ( final StackTraceElement aTrace : trace )
174             {
175                 s.println( "\tat " + aTrace );
176             }
177 
178             for ( int i = 0; i < numCauses; i++ )
179             {
180                 s.println( "Cause " + ( i + 1 ) + ":" );
181                 causes[i].printStackTrace( s );
182             }
183         }
184     }
185 
186     /**
187      * {@inheritDoc}
188      */
189     @Override
190     public String toString()
191     {
192         return super.toString() + " (caused by " + numCauses + " causes)";
193     }
194 
195 }