Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members   Related Pages  

Svc_Handler.cpp

Go to the documentation of this file.
00001 #include "ace_pch.h"
00002 // $Id: Svc_Handler.cpp,v 1.1.1.4.2.1 2003/03/13 19:44:22 chad Exp $
00003 
00004 #ifndef ACE_SVC_HANDLER_C
00005 #define ACE_SVC_HANDLER_C
00006 
00007 #include "ace/Svc_Handler.h"
00008 
00009 #if !defined (ACE_LACKS_PRAGMA_ONCE)
00010 # pragma once
00011 #endif /* ACE_LACKS_PRAGMA_ONCE */
00012 
00013 #include "ace/Object_Manager.h"
00014 #include "ace/Connection_Recycling_Strategy.h"
00015 
00016 #include "ace/Dynamic.h"
00017 
00018 ACE_RCSID(ace, Svc_Handler, "$Id: Svc_Handler.cpp,v 1.1.1.4.2.1 2003/03/13 19:44:22 chad Exp $")
00019 
00020 #define PR_ST_1 ACE_PEER_STREAM_1
00021 #define PR_ST_2 ACE_PEER_STREAM_2
00022 
00023 template <PR_ST_1, ACE_SYNCH_DECL> void *
00024 ACE_Svc_Handler<PR_ST_2,  ACE_SYNCH_USE>::operator new (size_t,
00025                                                         void *p)
00026 {
00027   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (NOOP, 2 parameters)");
00028   return p;
00029 }
00030 
00031 #if !defined (ACE_LACKS_PLACEMENT_OPERATOR_DELETE)
00032 template <PR_ST_1, ACE_SYNCH_DECL> void
00033 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (void *,
00034                                                           void *)
00035 {
00036   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (NOOP, 2 parameters)");
00037   return;
00038 }
00039 #endif /* ACE_LACKS_PLACEMENT_OPERATOR_DELETE */
00040 
00041 template <PR_ST_1, ACE_SYNCH_DECL> void *
00042 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (size_t n)
00043 {
00044   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new");
00045 
00046   ACE_Dynamic *const dynamic_instance = ACE_Dynamic::instance ();
00047 
00048   if (dynamic_instance == 0)
00049     {
00050       // If this ACE_ASSERT fails, it may be due to running of out TSS
00051       // keys.  Try using ACE_HAS_TSS_EMULATION, or increasing
00052       // ACE_DEFAULT_THREAD_KEYS if already using TSS emulation.
00053       ACE_ASSERT (dynamic_instance != 0);
00054 
00055       ACE_throw_bad_alloc;
00056     }
00057   else
00058     {
00059       // Allocate the memory and store it (usually in thread-specific
00060       // storage, depending on config flags).
00061       dynamic_instance->set ();
00062 
00063       return ::new char[n];
00064     }
00065 }
00066 
00067 #if defined (ACE_HAS_NEW_NOTHROW)
00068 template <PR_ST_1, ACE_SYNCH_DECL> void *
00069 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new (size_t n,
00070                                                        const ACE_nothrow_t&)
00071 {
00072   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator new(nothrow)");
00073 
00074   ACE_Dynamic *const dynamic_instance = ACE_Dynamic::instance ();
00075 
00076   if (dynamic_instance == 0)
00077     {
00078       // If this ACE_ASSERT fails, it may be due to running of out TSS
00079       // keys.  Try using ACE_HAS_TSS_EMULATION, or increasing
00080       // ACE_DEFAULT_THREAD_KEYS if already using TSS emulation.
00081       ACE_ASSERT (dynamic_instance != 0);
00082 
00083       return 0;
00084     }
00085   else
00086     {
00087       // Allocate the memory and store it (usually in thread-specific
00088       // storage, depending on config flags).
00089       dynamic_instance->set ();
00090 
00091       return ::new(ACE_nothrow) char[n];
00092     }
00093 }
00094 #endif /* ACE_HAS_NEW_NOTHROW */
00095 
00096 template <PR_ST_1, ACE_SYNCH_DECL> void
00097 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::destroy (void)
00098 {
00099   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::destroy");
00100 
00101   // Only delete ourselves if we're not owned by a module and have
00102   // been allocated dynamically.
00103   if (this->mod_ == 0 && this->dynamic_ && this->closing_ == 0)
00104     // Will call the destructor, which automatically calls <shutdown>.
00105     // Note that if we are *not* allocated dynamically then the
00106     // destructor will call <shutdown> automatically when it gets run
00107     // during cleanup.
00108     delete this;
00109 }
00110 
00111 template <PR_ST_1, ACE_SYNCH_DECL> void
00112 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete (void *obj)
00113 {
00114   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::operator delete");
00115   // You cannot delete a 'void*' (X3J16/95-0087 5.3.5.3), but we know
00116   // the pointer was created using new char[] (see operator new code),
00117   // so we use a cast:
00118   char *tmp = (char *) obj;
00119   ::delete [] tmp;
00120 }
00121 
00122 // Default constructor.
00123 
00124 template <PR_ST_1, ACE_SYNCH_DECL>
00125 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Svc_Handler (ACE_Thread_Manager *tm,
00126                                                           ACE_Message_Queue<ACE_SYNCH_USE> *mq,
00127                                                           ACE_Reactor *reactor)
00128   : ACE_Task<ACE_SYNCH_USE> (tm, mq),
00129     closing_ (0),
00130     recycler_ (0),
00131     recycling_act_ (0)
00132 {
00133   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Svc_Handler");
00134 
00135   this->reactor (reactor);
00136 
00137   // This clever idiom transparently checks if we were allocated
00138   // dynamically.  This information is used by the <destroy> method to
00139   // decide if we need to delete <this>...  The idiom is based on a
00140   // paper by Michael van Rooyen (mrooyen@cellnet.co.uk) that appeared
00141   // in the April '96 issue of the C++ Report.  We've spruced it up to
00142   // work correctly in multi-threaded programs by using our ACE_TSS
00143   // class.
00144   this->dynamic_ = ACE_Dynamic::instance ()->is_dynamic ();
00145 
00146   if (this->dynamic_ != 0)
00147     // Make sure to reset the flag.
00148     ACE_Dynamic::instance ()->reset ();
00149 }
00150 
00151 // Default behavior for a ACE_Svc_Handler object is to be registered
00152 // with the ACE_Reactor (thereby ensuring single threading).
00153 
00154 template <PR_ST_1, ACE_SYNCH_DECL> int
00155 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::open (void *)
00156 {
00157   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::open");
00158 #if defined (ACE_DEBUGGING)
00159   ACE_TCHAR buf[BUFSIZ];
00160   ACE_PEER_STREAM_ADDR client_addr;
00161 
00162   if (this->peer_.get_remote_addr (client_addr) == -1)
00163     ACE_ERROR_RETURN ((LM_ERROR,
00164                        ACE_LIB_TEXT ("%p\n"),
00165                        ACE_LIB_TEXT ("get_remote_addr")),
00166                       -1);
00167   else if (client_addr.addr_to_string (buf, sizeof buf) == -1)
00168     ACE_ERROR_RETURN ((LM_ERROR,
00169                        ACE_LIB_TEXT ("%p\n"),
00170                        ACE_LIB_TEXT ("can't obtain peer's address")),
00171                       -1);
00172   ACE_DEBUG ((LM_DEBUG,
00173               ACE_LIB_TEXT ("connected to %s on fd %d\n"),
00174               buf,
00175               this->peer_.get_handle ()));
00176 #endif /* ACE_DEBUGGING */
00177   if (this->reactor ()
00178       && this->reactor ()->register_handler
00179       (this,
00180        ACE_Event_Handler::READ_MASK) == -1)
00181     ACE_ERROR_RETURN ((LM_ERROR,
00182                        ACE_LIB_TEXT ("%p\n"),
00183                        ACE_LIB_TEXT ("unable to register client handler")),
00184                       -1);
00185   return 0;
00186 }
00187 
00188 // Perform termination activities.
00189 
00190 template <PR_ST_1, ACE_SYNCH_DECL> void
00191 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::shutdown (void)
00192 {
00193   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::shutdown");
00194 
00195   // Deregister this handler with the ACE_Reactor.
00196   if (this->reactor ())
00197     {
00198       ACE_Reactor_Mask mask = ACE_Event_Handler::ALL_EVENTS_MASK |
00199         ACE_Event_Handler::DONT_CALL;
00200 
00201       // Make sure there are no timers.
00202       this->reactor ()->cancel_timer (this);
00203 
00204       if (this->peer ().get_handle () != ACE_INVALID_HANDLE)
00205         // Remove self from reactor.
00206         this->reactor ()->remove_handler (this, mask);
00207     }
00208 
00209   // Remove self from the recycler.
00210   if (this->recycler ())
00211     this->recycler ()->purge (this->recycling_act_);
00212 
00213   this->peer ().close ();
00214 }
00215 
00216 template <PR_ST_1, ACE_SYNCH_DECL> void
00217 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::cleanup_hint (void **act_holder)
00218 {
00219   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::cleanup_hint");
00220 
00221   // Remove as hint.
00222   if (this->recycler ())
00223     this->recycler ()->cleanup_hint (this->recycling_act_,
00224                                      act_holder);
00225 }
00226 
00227 template <PR_ST_1, ACE_SYNCH_DECL> void
00228 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump (void) const
00229 {
00230   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump");
00231 
00232   this->peer_.dump ();
00233   ACE_DEBUG ((LM_DEBUG,
00234               "dynamic_ = %d\n",
00235               this->dynamic_));
00236   ACE_DEBUG ((LM_DEBUG,
00237               "closing_ = %d\n",
00238               this->closing_));
00239   ACE_DEBUG ((LM_DEBUG,
00240               "recycler_ = %d\n",
00241               this->recycler_));
00242   ACE_DEBUG ((LM_DEBUG,
00243               "recycling_act_ = %d\n",
00244               this->recycling_act_));
00245 }
00246 
00247 template <PR_ST_1, ACE_SYNCH_DECL> ACE_PEER_STREAM &
00248 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::peer (void) const
00249 {
00250   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::peer");
00251   return (ACE_PEER_STREAM &) this->peer_;
00252 }
00253 
00254 // Extract the underlying I/O descriptor.
00255 
00256 template <PR_ST_1, ACE_SYNCH_DECL> ACE_HANDLE
00257 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::get_handle (void) const
00258 {
00259   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::get_handle");
00260   return this->peer_.get_handle ();
00261 }
00262 
00263 // Set the underlying I/O descriptor.
00264 
00265 template <PR_ST_1, ACE_SYNCH_DECL> void
00266 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::set_handle (ACE_HANDLE h)
00267 {
00268   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::set_handle");
00269   this->peer_.set_handle (h);
00270 }
00271 
00272 template <PR_ST_1, ACE_SYNCH_DECL>
00273 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Svc_Handler (void)
00274 {
00275   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Svc_Handler");
00276 
00277   if (this->closing_ == 0)
00278     {
00279       // We're closing down now, so make sure not to call ourselves
00280       // recursively via other calls to handle_close() (e.g., from the
00281       // Timer_Queue).
00282       this->closing_ = 1;
00283 
00284       this->shutdown ();
00285     }
00286 }
00287 
00288 template <PR_ST_1, ACE_SYNCH_DECL> int
00289 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_close (ACE_HANDLE,
00290                                                        ACE_Reactor_Mask)
00291 {
00292   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_close");
00293 
00294   this->destroy ();
00295   return 0;
00296 }
00297 
00298 template <PR_ST_1, ACE_SYNCH_DECL> int
00299 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout (const ACE_Time_Value &,
00300                                                          const void *)
00301 {
00302   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout");
00303   return this->handle_close ();
00304 }
00305 
00306 template <PR_ST_1, ACE_SYNCH_DECL> int
00307 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::close (u_long)
00308 {
00309   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::close");
00310   return this->handle_close ();
00311 }
00312 
00313 template <PR_ST_1, ACE_SYNCH_DECL> int
00314 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::init (int argc, ACE_TCHAR *argv[])
00315 {
00316   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::init");
00317   ACE_UNUSED_ARG (argc);
00318   ACE_UNUSED_ARG (argv);
00319   return -1;
00320 }
00321 
00322 template <PR_ST_1, ACE_SYNCH_DECL> int
00323 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::fini (void)
00324 {
00325   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::fini");
00326   return -1;
00327 }
00328 
00329 template <PR_ST_1, ACE_SYNCH_DECL> int
00330 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::info (ACE_TCHAR **, size_t) const
00331 {
00332   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::info");
00333   return -1;
00334 }
00335 
00336 template <PR_ST_1, ACE_SYNCH_DECL> int
00337 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::idle (u_long flags)
00338 {
00339   if (this->recycler ())
00340     return this->recycler ()->cache (this->recycling_act_);
00341   else
00342     return this->close (flags);
00343 }
00344 
00345 template <PR_ST_1, ACE_SYNCH_DECL> int
00346 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle_state (ACE_Recyclable_State new_state)
00347 {
00348   if (this->recycler ())
00349     return this->recycler ()->recycle_state (this->recycling_act_,
00350                                              new_state);
00351 
00352   return 0;
00353 }
00354 
00355 template <PR_ST_1, ACE_SYNCH_DECL> ACE_Recyclable_State
00356 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle_state (void) const
00357 {
00358   if (this->recycler ())
00359     return this->recycler ()->recycle_state (this->recycling_act_);
00360 
00361   return ACE_RECYCLABLE_UNKNOWN;
00362 }
00363 
00364 template <PR_ST_1, ACE_SYNCH_DECL> void
00365 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler (ACE_Connection_Recycling_Strategy *recycler,
00366                                                    const void *recycling_act)
00367 {
00368   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler");
00369   this->recycler_ = recycler;
00370   this->recycling_act_ = recycling_act;
00371 }
00372 
00373 template <PR_ST_1, ACE_SYNCH_DECL> ACE_Connection_Recycling_Strategy *
00374 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler (void) const
00375 {
00376   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycler");
00377   return this->recycler_;
00378 }
00379 
00380 template <PR_ST_1, ACE_SYNCH_DECL> const void *
00381 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycling_act (void) const
00382 {
00383   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycling_act");
00384   return this->recycling_act_;
00385 }
00386 
00387 template <PR_ST_1, ACE_SYNCH_DECL> int
00388 ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle (void *)
00389 {
00390   ACE_TRACE ("ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::recycle");
00391   // By default, the object is ready and willing to be recycled.
00392   return 0;
00393 }
00394 
00395 template <PR_ST_1, ACE_SYNCH_DECL>
00396 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::~ACE_Buffered_Svc_Handler (void)
00397 {
00398   this->flush ();
00399 }
00400 
00401 template <PR_ST_1, ACE_SYNCH_DECL>
00402 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Buffered_Svc_Handler (ACE_Thread_Manager *tm,
00403                                                                             ACE_Message_Queue<ACE_SYNCH_USE> *mq,
00404                                                                             ACE_Reactor *reactor,
00405                                                                             size_t maximum_buffer_size,
00406                                                                             ACE_Time_Value *timeout)
00407   : ACE_Svc_Handler<PR_ST_2, ACE_SYNCH_USE> (tm, mq, reactor),
00408     maximum_buffer_size_ (maximum_buffer_size),
00409     current_buffer_size_ (0),
00410     timeoutp_ (timeout)
00411 {
00412   ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::ACE_Buffered_Svc_Handler");
00413 
00414   if (this->timeoutp_ != 0)
00415     {
00416       this->interval_ = *timeout;
00417       this->next_timeout_ = ACE_OS::gettimeofday () + this->interval_;
00418     }
00419 }
00420 
00421 template <PR_ST_1, ACE_SYNCH_DECL> int
00422 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::put (ACE_Message_Block *mb,
00423                                                        ACE_Time_Value *tv)
00424 {
00425   ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->msg_queue ()->lock (), -1);
00426 
00427   // Enqueue <mb> onto the message queue.
00428   if (this->putq (mb, tv) == -1)
00429     return -1;
00430   else
00431     {
00432       // Update the current number of bytes on the queue.
00433       this->current_buffer_size_ += mb->total_size ();
00434 
00435       // Flush the buffer when the number of bytes exceeds the maximum
00436       // buffer size or when the timeout period has elapsed.
00437       if (this->current_buffer_size_ >= this->maximum_buffer_size_
00438           || (this->timeoutp_ != 0
00439               && this->next_timeout_ <= ACE_OS::gettimeofday ()))
00440         return this->flush_i ();
00441       else
00442         return 0;
00443     }
00444 }
00445 
00446 // Flush the buffer.
00447 
00448 template <PR_ST_1, ACE_SYNCH_DECL> int
00449 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::flush (void)
00450 {
00451   ACE_GUARD_RETURN (ACE_SYNCH_MUTEX_T, m, this->msg_queue ()->lock (), -1);
00452 
00453   return this->flush_i ();
00454 }
00455 
00456 template <PR_ST_1, ACE_SYNCH_DECL> int
00457 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::flush_i (void)
00458 {
00459   ACE_Message_Queue_Iterator<ACE_SYNCH_USE> iterator (*this->msg_queue ());
00460   ACE_Message_Block *mblk;
00461   int result = 0;
00462 
00463   // Get the first <ACE_Message_Block> so that we can write everything
00464   // out via the <send_n>.
00465   if (iterator.next (mblk) != 0)
00466     result = this->peer ().send_n (mblk);
00467 
00468   // This method assumes the caller holds the queue's lock!
00469   if (result != -1)
00470     this->msg_queue ()->flush_i ();
00471 
00472   if (this->timeoutp_ != 0)
00473     // Update the next timeout period by adding the interval.
00474     this->next_timeout_ += this->interval_;
00475 
00476   this->current_buffer_size_ = 0;
00477 
00478   return result;
00479 }
00480 
00481 template <PR_ST_1, ACE_SYNCH_DECL> void
00482 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump (void) const
00483 {
00484   ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump");
00485 
00486   ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::dump ();
00487   ACE_DEBUG ((LM_DEBUG,
00488               "maximum_buffer_size_ = %d\n",
00489               this->maximum_buffer_size_));
00490   ACE_DEBUG ((LM_DEBUG,
00491               "current_buffer_size_ = %d\n",
00492               this->current_buffer_size_));
00493   if (this->timeoutp_ != 0)
00494     ACE_DEBUG ((LM_DEBUG,
00495                 "next_timeout_.sec = %d, next_timeout_.usec = %d\n",
00496                 this->next_timeout_.sec (),
00497                 this->next_timeout_.usec ()));
00498 }
00499 
00500 template <PR_ST_1, ACE_SYNCH_DECL> int
00501 ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout (const ACE_Time_Value &,
00502                                                                   const void *)
00503 {
00504   ACE_TRACE ("ACE_Buffered_Svc_Handler<PR_ST_2, ACE_SYNCH_USE>::handle_timeout");
00505   return 0;
00506 }
00507 
00508 #undef PR_ST_1
00509 #undef PR_ST_2
00510 #endif /* ACE_SVC_HANDLER_C */

Generated on Mon Jun 16 11:21:35 2003 for ACE by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002