Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/derby/iapi/services/context/ContextManager.java


1   /*
2   
3      Derby - Class org.apache.derby.iapi.services.context.ContextManager
4   
5      Copyright 1997, 2004 The Apache Software Foundation or its licensors, as applicable.
6   
7      Licensed under the Apache License, Version 2.0 (the "License");
8      you may not use this file except in compliance with the License.
9      You may obtain a copy of the License at
10  
11        http://www.apache.org/licenses/LICENSE-2.0
12  
13     Unless required by applicable law or agreed to in writing, software
14     distributed under the License is distributed on an "AS IS" BASIS,
15     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16     See the License for the specific language governing permissions and
17     limitations under the License.
18  
19   */
20  
21  package org.apache.derby.iapi.services.context;
22  
23  import org.apache.derby.iapi.services.sanity.SanityManager;
24  import org.apache.derby.iapi.services.stream.HeaderPrintWriter;
25  import org.apache.derby.iapi.services.stream.PrintWriterGetHeader;
26  
27  import org.apache.derby.iapi.error.PassThroughException;
28  
29  import org.apache.derby.iapi.error.StandardException;
30  import org.apache.derby.iapi.services.monitor.Monitor;
31  
32  import org.apache.derby.iapi.reference.Property;
33  import org.apache.derby.iapi.services.property.PropertyUtil;
34  
35  import org.apache.derby.iapi.error.ExceptionSeverity;
36  import org.apache.derby.iapi.reference.SQLState;
37  import org.apache.derby.iapi.services.i18n.LocaleFinder;
38  import java.io.PrintWriter;
39  
40  import java.util.Hashtable;
41  import java.util.Stack;
42  import java.util.Vector;
43  import java.util.Locale;
44  
45  /**
46   *
47   * The ContextManager collects contexts as they are
48   * created. It maintains stacks of contexts by
49   * named ids, so that the top context of a given
50   * type can be returned. It also maintains a global
51   * stack so that contexts can be traversed in the
52   * order they were created.
53   * <p>
54   * The first implementation of the context manager
55   * assumes there is only one thread to worry about
56   * and that the user(s) of the class only create one
57   * instance of ContextManager.
58   */
59  
60  public class ContextManager
61  
62  {
63  
64  
65    private final Stack holder;
66  
67    /*
68     * ContextManager interface
69     */
70  
71    public void pushContext(Context newContext)
72    {
73      checkInterrupt();
74  
75      String contextId = newContext.getIdName();
76  
77      Stack idStack = (Stack) ctxTable.get(contextId);
78  
79      // if the stack is null, create a new one.
80      if (idStack == null)
81      {
82        idStack = new Stack();
83        ctxTable.put(contextId,idStack);
84      }
85  
86      // add to top of id's stack
87      idStack.push(newContext);
88  
89      // add to top of global stack too
90      holder.push(newContext);
91    }
92  
93    /**
94     * @see org.apache.derby.iapi.services.context.ContextManager#getContext
95     */
96    public Context getContext(String contextId)
97    {
98      checkInterrupt();
99  
100     Stack idStack = (Stack)ctxTable.get(contextId);
101 
102     if (SanityManager.DEBUG)
103     SanityManager.ASSERT( idStack == null ||
104       idStack.empty() ||
105       ((Context)idStack.peek()).getIdName().equals(contextId));
106 
107     if (idStack == null ||
108         idStack.empty())
109     {
110       return null;
111     }
112 
113 
114 
115     return (Context) idStack.peek();
116   }
117 
118   /**
119    * @see org.apache.derby.iapi.services.context.ContextManager#popContext
120    */
121   public void popContext()
122   {
123     checkInterrupt();
124 
125     Context theContext;
126     String contextId;
127     Stack idStack;
128 
129     // no contexts to remove, so we're done.
130     if (holder.empty())
131     {
132       return;
133     }
134 
135     // remove the top context from the global stack
136     theContext = (Context) holder.pop();
137 
138     // now find its id and remove it from there, too
139     contextId = theContext.getIdName();
140     idStack = (Stack)ctxTable.get(contextId);
141 
142     if (SanityManager.DEBUG)
143     SanityManager.ASSERT( idStack != null &&
144       (! idStack.empty()) &&
145       ((Context)idStack.peek()).getIdName() == contextId);
146 
147     idStack.pop();
148   }
149 
150   void popContext(Context theContext)
151   {
152     checkInterrupt();
153 
154     Stack idStack;
155 
156     if (SanityManager.DEBUG)
157     SanityManager.ASSERT(!holder.empty());
158 
159     // first, remove it from the global stack.
160     // to do this we treat it like its vector supertype.
161     int index = holder.lastIndexOf(theContext);
162     if (index != -1)
163       holder.removeElementAt(index);
164     else if (SanityManager.DEBUG) {
165       //SanityManager.THROWASSERT("Popped non-existent context by id " + theContext + " type " + theContext.getIdName());
166     }
167 
168     // now remove it from its id's stack.
169     idStack = (Stack) ctxTable.get(theContext.getIdName());
170     boolean wasThere = idStack.removeElement(theContext);
171     if (SanityManager.DEBUG) {
172       //if (!wasThere)
173       //  SanityManager.THROWASSERT("Popped non-existent stack by id " + theContext + " type " + theContext.getIdName());
174     }
175   }
176 
177   /**
178     @return true if the context manager is shutdown, false otherwise.
179    */
180   public boolean cleanupOnError(Throwable error)
181   {
182     if (shutdown)
183       return true;
184 
185     if (errorStringBuilder == null)
186       errorStringBuilder = new ErrorStringBuilder(errorStream.getHeader());
187 
188     ThreadDeath seenThreadDeath = null;
189     if (error instanceof ThreadDeath)
190       seenThreadDeath = (ThreadDeath) error;
191 
192     if (error instanceof PassThroughException)
193       error = ((PassThroughException) error).getException();
194 
195     boolean reportError = reportError(error);
196 
197     if (reportError) 
198     {
199       ContextImpl lcc = null;
200       StringBuffer sb = null;
201       if (! shutdown)
202       {
203         // report an id for the message if possible
204         lcc = (ContextImpl) getContext(org.apache.derby.iapi.reference.ContextId.LANG_CONNECTION);
205         if (lcc != null) {
206           sb = lcc.appendErrorInfo();
207         }
208       }
209 
210       String cleanup = "Cleanup action starting";
211 
212       if (sb != null) {
213         sb.append(cleanup);
214         cleanup = sb.toString();
215       }
216 
217       errorStringBuilder.appendln(cleanup);
218       
219       if (!shutdown)    // Do this only during normal processing.
220       {  
221         ContextImpl sc = (ContextImpl) getContext(org.apache.derby.iapi.reference.ContextId.LANG_STATEMENT);
222         // Output the SQL statement that failed in the log file.
223         if (sc != null)
224         {          
225           sb = sc.appendErrorInfo();
226           if (sb != null)
227             errorStringBuilder.appendln(sb.toString());
228         }
229       }
230     }
231     
232     /*
233       REVISIT RESOLVE
234       Ensure that the traversal of the stack works in all 
235       cases where contexts can  pop themselves *and* 
236       contexts can pop other contexts off the stack.
237     */ 
238     
239 
240 forever: for (;;) {
241 
242       int errorSeverity = error instanceof StandardException ?
243         ((StandardException) error).getSeverity() :
244         ExceptionSeverity.NO_APPLICABLE_SEVERITY;
245        if (reportError) {
246         errorStringBuilder.stackTrace(error);
247         flushErrorString();
248       }
249 
250       
251       boolean  lastHandler = false;
252 
253 
254       /*
255         Walk down the stack, calling
256         cleanup on each context. We use
257         the vector interface to do this.
258        */
259 cleanup:  for (int index = holder.size() - 1; index >= 0; index--) {
260 
261         try {
262           if (lastHandler)
263           {
264             break;
265           }
266 
267           Context ctx = ((Context) holder.elementAt(index));
268           lastHandler = ctx.isLastHandler(errorSeverity);
269 
270           ctx.cleanupOnError(error);
271         }
272         catch (StandardException se) {
273   
274           if (error instanceof StandardException) {
275   
276             if (se.getSeverity() > ((StandardException) error).getSeverity()) {
277               // Ok, error handling raised a more severe error,
278               // restart with the more severe error
279               error = se;
280               reportError = reportError(se);
281               if (reportError) {
282                 errorStream.println("New exception raised during cleanup " + error.getMessage());
283                 errorStream.flush();
284               }
285               continue forever;
286             }
287           }
288 
289           if (reportError(se)) {
290             errorStringBuilder.appendln("Less severe exception raised during cleanup (ignored) " + se.getMessage());
291             errorStringBuilder.stackTrace(se);
292             flushErrorString();
293           }
294 
295           /*
296             For a less severe error, keep with the last error
297            */
298           continue cleanup;
299         }
300         catch (Throwable t) {
301           reportError = reportError(t);
302 
303 
304           if (error instanceof StandardException) {
305             /*
306               Ok, error handling raised a more severe error,
307               restart with the more severe error
308               A Throwable after a StandardException is always 
309               more severe.
310              */
311             error = t;
312             if (reportError) {
313               errorStream.println("New exception raised during cleanup " + error.getMessage());
314               errorStream.flush();
315             }
316             continue forever;
317           }
318 
319 
320           if (reportError) {
321             errorStringBuilder.appendln("Equally severe exception raised during cleanup (ignored) " + t.getMessage());
322             errorStringBuilder.stackTrace(t);
323             flushErrorString();
324           }
325 
326           if (t instanceof ThreadDeath) {
327             if (seenThreadDeath != null)
328               throw seenThreadDeath;
329 
330             seenThreadDeath = (ThreadDeath) t;
331           }
332   
333           /*
334             For a less severe error, just continue with the last
335             error
336            */
337           continue cleanup;
338         }
339       }
340 
341       if (reportError) {
342         errorStream.println("Cleanup action completed");
343         errorStream.flush();
344       }
345 
346       if (seenThreadDeath != null)
347         throw seenThreadDeath;
348 
349       return false;
350     }
351 
352   }
353 
354 
355   synchronized boolean  setInterrupted(Context c) {
356 
357     boolean interruptMe = (c == null) || holder.contains(c);
358 
359     if (interruptMe) {
360       this.shutdown = true;
361     }
362     return interruptMe;
363   }
364 
365   /**
366     Check to see if we have been interrupted. If we have then
367     a ShutdownException will be thrown. This will be either the
368     one passed to interrupt or a generic one if some outside
369     source interrupted the thread.
370   */
371   private void checkInterrupt() {
372     if (shutdown) {
373       // system must have changed underneath us
374       throw new ShutdownException();
375     }
376   }
377 
378   /**
379     Set the locale for this context.
380   */
381   public void setLocaleFinder(LocaleFinder finder) {
382     this.finder = finder;
383   }
384 
385   private Locale messageLocale;
386 
387   public void setMessageLocale(String localeID) throws StandardException {
388     this.messageLocale = Monitor.getLocaleFromString(localeID);
389   }
390 
391   public Locale getMessageLocale()
392   {
393     if (messageLocale != null)
394       return messageLocale;
395     else if (finder != null) {
396       try {
397         return finder.getCurrentLocale();
398       } catch (StandardException se) {
399         
400       }
401     }
402     return Locale.getDefault();
403   }
404 
405   /**
406    * Flush the built up error string to whereever
407    * it is supposed to go, and reset the error string
408    */
409   private void flushErrorString()
410   {
411     errorStream.print(errorStringBuilder.get().toString());
412     errorStream.flush();
413     errorStringBuilder.reset();
414   }
415 
416   /*
417   ** Class methods
418   */
419 
420   private boolean reportError(Throwable t) {
421 
422     if (t instanceof StandardException) {
423 
424       StandardException se = (StandardException) t;
425 
426       switch (se.report()) {
427       case StandardException.REPORT_DEFAULT:
428         int level = se.getSeverity();
429         return (level >= logSeverityLevel) ||
430           (level == ExceptionSeverity.NO_APPLICABLE_SEVERITY);
431 
432       case StandardException.REPORT_NEVER:
433         return false;
434 
435       case StandardException.REPORT_ALWAYS:
436       default:
437         return true;
438       }
439     }
440 
441     return !(t instanceof ShutdownException);
442 
443   }
444 
445   /**
446    * constructor specifying the hash table size and load
447    * factor for the hashed-by-id context stacks.
448    */
449   ContextManager(ContextService csf, HeaderPrintWriter stream)
450   {
451     errorStream = stream;
452     ctxTable = new Hashtable();
453     owningCsf = csf;
454 
455     logSeverityLevel = PropertyUtil.getSystemInt(Property.LOG_SEVERITY_LEVEL,
456       SanityManager.DEBUG ? 0 : ExceptionSeverity.SESSION_SEVERITY);
457 
458     holder = new Stack();
459   }
460 
461   private final Hashtable ctxTable;
462 
463   final ContextService owningCsf;
464 
465   private int    logSeverityLevel;
466 
467   private HeaderPrintWriter errorStream;
468   private ErrorStringBuilder errorStringBuilder;
469 
470   private boolean shutdown;
471   private LocaleFinder finder;
472 
473   final Stack cmStack = new Stack();
474 
475   Thread  activeThread;
476   int    activeCount;
477 }