]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/util/component/ContainerLifeCycle.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / util / component / ContainerLifeCycle.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.util.component;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.List;
26 import java.util.concurrent.CopyOnWriteArrayList;
27
28 import org.eclipse.jetty.util.annotation.ManagedObject;
29 import org.eclipse.jetty.util.annotation.ManagedOperation;
30 import org.eclipse.jetty.util.log.Log;
31 import org.eclipse.jetty.util.log.Logger;
32
33 /**
34  * An ContainerLifeCycle is an {@link LifeCycle} implementation for a collection of contained beans.
35  * <p>
36  * Beans can be added the ContainerLifeCycle either as managed beans or as unmanaged beans.  A managed bean is started, stopped and destroyed with the aggregate.
37  * An unmanaged bean is associated with the aggregate for the purposes of {@link #dump()}, but it's lifecycle must be managed externally.
38  * <p>
39  * When a {@link LifeCycle} bean is added without a managed state being specified the state is determined heuristically:
40  * <ul>
41  *   <li>If the added bean is running, it will be added as an unmanaged bean.
42  *   <li>If the added bean is !running and the container is !running, it will be added as an AUTO bean (see below).
43  *   <li>If the added bean is !running and the container is starting, it will be added as an managed bean and will be started (this handles the frequent case of 
44  *   new beans added during calls to doStart).
45  *   <li>If the added bean is !running and the container is started, it will be added as an unmanaged bean.
46  * </ul>
47  * When the container is started, then all contained managed beans will also be started.  Any contained Auto beans 
48  * will be check for their status and if already started will be switched unmanaged beans, else they will be 
49  * started and switched to managed beans.  Beans added after a container is started are not started and their state needs to
50  * be explicitly managed.
51  * <p>
52  * When stopping the container, a contained bean will be stopped by this aggregate only if it
53  * is started by this aggregate.
54  * <p>
55  * The methods {@link #addBean(Object, boolean)}, {@link #manage(Object)} and {@link #unmanage(Object)} can be used to
56  * explicitly control the life cycle relationship.
57  * <p>
58  * If adding a bean that is shared between multiple {@link ContainerLifeCycle} instances, then it should be started before being added, so it is unmanaged, or
59  * the API must be used to explicitly set it as unmanaged.
60  * <p>
61  * This class also provides utility methods to dump deep structures of objects.  It the dump, the following symbols are used to indicate the type of contained object:
62  * <pre>
63  * SomeContainerLifeCycleInstance
64  *   +- contained POJO instance
65  *   += contained MANAGED object, started and stopped with this instance
66  *   +~ referenced UNMANAGED object, with separate lifecycle
67  *   +? referenced AUTO object that could become MANAGED or UNMANAGED.
68  * </pre>
69  */
70
71 /* ------------------------------------------------------------ */
72 /**
73  */
74 @ManagedObject("Implementation of Container and LifeCycle")
75 public class ContainerLifeCycle extends AbstractLifeCycle implements Container, Destroyable, Dumpable
76 {
77     private static final Logger LOG = Log.getLogger(ContainerLifeCycle.class);
78     private final List<Bean> _beans = new CopyOnWriteArrayList<>();
79     private final List<Container.Listener> _listeners = new CopyOnWriteArrayList<>();
80     private boolean _doStarted = false;
81
82
83     public ContainerLifeCycle()
84     {
85     }
86
87     /**
88      * Starts the managed lifecycle beans in the order they were added.
89      */
90     @Override
91     protected void doStart() throws Exception
92     {
93         // indicate that we are started, so that addBean will start other beans added.
94         _doStarted = true;
95
96         // start our managed and auto beans
97         for (Bean b : _beans)
98         {
99             if (b._bean instanceof LifeCycle)
100             {
101                 LifeCycle l = (LifeCycle)b._bean;
102                 switch(b._managed)
103                 {
104                     case MANAGED:
105                         if (!l.isRunning())
106                             start(l);
107                         break;
108                     case AUTO:
109                         if (l.isRunning())
110                             unmanage(b);
111                         else
112                         {
113                             manage(b);
114                             start(l);
115                         }
116                         break;
117                 }
118             }
119         }
120
121         super.doStart();
122     }
123
124     /**
125      * Starts the given lifecycle.
126      *
127      * @param l
128      * @throws Exception
129      */
130     protected void start(LifeCycle l) throws Exception
131     {
132         l.start();
133     }
134     
135     /**
136      * Stops the given lifecycle.
137      *
138      * @param l
139      * @throws Exception
140      */
141     protected void stop(LifeCycle l) throws Exception
142     {
143         l.stop();
144     }
145
146     /**
147      * Stops the managed lifecycle beans in the reverse order they were added.
148      */
149     @Override
150     protected void doStop() throws Exception
151     {
152         _doStarted = false;
153         super.doStop();
154         List<Bean> reverse = new ArrayList<>(_beans);
155         Collections.reverse(reverse);
156         for (Bean b : reverse)
157         {
158             if (b._managed==Managed.MANAGED && b._bean instanceof LifeCycle)
159             {
160                 LifeCycle l = (LifeCycle)b._bean;
161                 if (l.isRunning())
162                     stop(l);
163             }
164         }
165     }
166
167     /**
168      * Destroys the managed Destroyable beans in the reverse order they were added.
169      */
170     @Override
171     public void destroy()
172     {
173         List<Bean> reverse = new ArrayList<>(_beans);
174         Collections.reverse(reverse);
175         for (Bean b : reverse)
176         {
177             if (b._bean instanceof Destroyable && (b._managed==Managed.MANAGED || b._managed==Managed.POJO))
178             {
179                 Destroyable d = (Destroyable)b._bean;
180                 d.destroy();
181             }
182         }
183         _beans.clear();
184     }
185
186
187     /**
188      * @param bean the bean to test
189      * @return whether this aggregate contains the bean
190      */
191     public boolean contains(Object bean)
192     {
193         for (Bean b : _beans)
194             if (b._bean == bean)
195                 return true;
196         return false;
197     }
198
199     /**
200      * @param bean the bean to test
201      * @return whether this aggregate contains and manages the bean
202      */
203     public boolean isManaged(Object bean)
204     {
205         for (Bean b : _beans)
206             if (b._bean == bean)
207                 return b.isManaged();
208         return false;
209     }
210
211     /**
212      * Adds the given bean, detecting whether to manage it or not.
213      * If the bean is a {@link LifeCycle}, then it will be managed if it is not
214      * already started and not managed if it is already started.
215      * The {@link #addBean(Object, boolean)}
216      * method should be used if this is not correct, or the {@link #manage(Object)} and {@link #unmanage(Object)}
217      * methods may be used after an add to change the status.
218      *
219      * @param o the bean object to add
220      * @return true if the bean was added, false if it was already present
221      */
222     @Override
223     public boolean addBean(Object o)
224     {
225         if (o instanceof LifeCycle)
226         {
227             LifeCycle l = (LifeCycle)o;
228             return addBean(o,l.isRunning()?Managed.UNMANAGED:Managed.AUTO);
229         }
230
231         return addBean(o,Managed.POJO);
232     }
233
234     /**
235      * Adds the given bean, explicitly managing it or not.
236      *
237      * @param o       The bean object to add
238      * @param managed whether to managed the lifecycle of the bean
239      * @return true if the bean was added, false if it was already present
240      */
241     public boolean addBean(Object o, boolean managed)
242     {
243         if (o instanceof LifeCycle)
244             return addBean(o,managed?Managed.MANAGED:Managed.UNMANAGED);
245         return addBean(o,managed?Managed.POJO:Managed.UNMANAGED);
246     }
247
248     public boolean addBean(Object o, Managed managed)
249     {
250         if (contains(o))
251             return false;
252
253         Bean new_bean = new Bean(o);
254
255         // if the bean is a Listener
256         if (o instanceof Container.Listener)
257             addEventListener((Container.Listener)o);
258
259         // Add the bean
260         _beans.add(new_bean);
261
262         // Tell existing listeners about the new bean
263         for (Container.Listener l:_listeners)
264             l.beanAdded(this,o);
265
266         try
267         {
268             switch (managed)
269             {
270                 case UNMANAGED:
271                     unmanage(new_bean);
272                     break;
273
274                 case MANAGED:
275                     manage(new_bean);
276
277                     if (isStarting() && _doStarted)
278                     {
279                         LifeCycle l = (LifeCycle)o;
280                         if (!l.isRunning())
281                             start(l);
282                     }
283                     break;
284
285                 case AUTO:
286                     if (o instanceof LifeCycle)
287                     {
288                         LifeCycle l = (LifeCycle)o;
289                         if (isStarting())
290                         {
291                             if (l.isRunning())
292                                 unmanage(new_bean);
293                             else if (_doStarted)
294                             {
295                                 manage(new_bean);
296                                 start(l);
297                             }
298                             else
299                                 new_bean._managed=Managed.AUTO;      
300                         }
301                         else if (isStarted())
302                             unmanage(new_bean);
303                         else
304                             new_bean._managed=Managed.AUTO;
305                     }
306                     else
307                         new_bean._managed=Managed.POJO;
308                     break;
309
310                 case POJO:
311                     new_bean._managed=Managed.POJO;
312             }
313         }
314         catch (RuntimeException | Error e)
315         {
316             throw e;
317         }
318         catch (Exception e)
319         {
320             throw new RuntimeException(e);
321         }
322
323         LOG.debug("{} added {}",this,new_bean);
324
325         return true;
326     }
327
328     
329     /* ------------------------------------------------------------ */
330     /** Add a managed lifecycle.
331      * <p>This is a conveniance method that uses addBean(lifecycle,true)
332      * and then ensures that the added bean is started iff this container
333      * is running.  Exception from nested calls to start are caught and 
334      * wrapped as RuntimeExceptions
335      * @param lifecycle
336      */
337     public void addManaged(LifeCycle lifecycle)
338     {
339         addBean(lifecycle,true);
340         try
341         {
342             if (isRunning() && !lifecycle.isRunning())
343                 start(lifecycle);
344         }
345         catch (RuntimeException | Error e)
346         {
347             throw e;
348         }
349         catch (Exception e)
350         {
351             throw new RuntimeException(e);
352         }
353     }
354
355     @Override
356     public void addEventListener(Container.Listener listener)
357     {
358         if (_listeners.contains(listener))
359             return;
360         
361         _listeners.add(listener);
362
363         // tell it about existing beans
364         for (Bean b:_beans)
365         {
366             listener.beanAdded(this,b._bean);
367
368             // handle inheritance
369             if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
370             {
371                 if (b._bean instanceof ContainerLifeCycle)
372                      ((ContainerLifeCycle)b._bean).addBean(listener, false);
373                  else
374                      ((Container)b._bean).addBean(listener);
375             }
376         }
377     }
378
379     /**
380      * Manages a bean already contained by this aggregate, so that it is started/stopped/destroyed with this
381      * aggregate.
382      *
383      * @param bean The bean to manage (must already have been added).
384      */
385     public void manage(Object bean)
386     {
387         for (Bean b : _beans)
388         {
389             if (b._bean == bean)
390             {
391                 manage(b);
392                 return;
393             }
394         }
395         throw new IllegalArgumentException("Unknown bean " + bean);
396     }
397
398     private void manage(Bean bean)
399     {
400         if (bean._managed!=Managed.MANAGED)
401         {
402             bean._managed=Managed.MANAGED;
403
404             if (bean._bean instanceof Container)
405             {
406                 for (Container.Listener l:_listeners)
407                 {
408                     if (l instanceof InheritedListener)
409                     {
410                         if (bean._bean instanceof ContainerLifeCycle)
411                             ((ContainerLifeCycle)bean._bean).addBean(l,false);
412                         else
413                             ((Container)bean._bean).addBean(l);
414                     }
415                 }
416             }
417
418             if (bean._bean instanceof AbstractLifeCycle)
419             {
420                 ((AbstractLifeCycle)bean._bean).setStopTimeout(getStopTimeout());
421             }
422         }
423     }
424
425     /**
426      * Unmanages a bean already contained by this aggregate, so that it is not started/stopped/destroyed with this
427      * aggregate.
428      *
429      * @param bean The bean to unmanage (must already have been added).
430      */
431     public void unmanage(Object bean)
432     {
433         for (Bean b : _beans)
434         {
435             if (b._bean == bean)
436             {
437                 unmanage(b);
438                 return;
439             }
440         }
441         throw new IllegalArgumentException("Unknown bean " + bean);
442     }
443
444     private void unmanage(Bean bean)
445     {
446         if (bean._managed!=Managed.UNMANAGED)
447         {
448             if (bean._managed==Managed.MANAGED && bean._bean instanceof Container)
449             {
450                 for (Container.Listener l:_listeners)
451                 {
452                     if (l instanceof InheritedListener)
453                         ((Container)bean._bean).removeBean(l);
454                 }
455             }
456             bean._managed=Managed.UNMANAGED;
457         }
458     }
459
460     @Override
461     public Collection<Object> getBeans()
462     {
463         return getBeans(Object.class);
464     }
465
466     public void setBeans(Collection<Object> beans)
467     {
468         for (Object bean : beans)
469             addBean(bean);
470     }
471
472     @Override
473     public <T> Collection<T> getBeans(Class<T> clazz)
474     {
475         ArrayList<T> beans = new ArrayList<>();
476         for (Bean b : _beans)
477         {
478             if (clazz.isInstance(b._bean))
479                 beans.add(clazz.cast(b._bean));
480         }
481         return beans;
482     }
483
484     @Override
485     public <T> T getBean(Class<T> clazz)
486     {
487         for (Bean b : _beans)
488         {
489             if (clazz.isInstance(b._bean))
490                 return clazz.cast(b._bean);
491         }
492         return null;
493     }
494
495     /**
496      * Removes all bean
497      */
498     public void removeBeans()
499     {
500         ArrayList<Bean> beans= new ArrayList<>(_beans);
501         for (Bean b : beans)
502             remove(b);
503     }
504
505     private Bean getBean(Object o)
506     {
507         for (Bean b : _beans)
508         {
509             if (b._bean == o)
510                 return b;
511         }
512         return null;
513     }
514
515     @Override
516     public boolean removeBean(Object o)
517     {
518         Bean b=getBean(o);
519         return b!=null && remove(b);
520     }
521
522     private boolean remove(Bean bean)
523     {
524         if (_beans.remove(bean))
525         {
526             
527             unmanage(bean);
528
529             for (Container.Listener l:_listeners)
530                 l.beanRemoved(this,bean._bean);
531
532             if (bean._bean instanceof Container.Listener)
533                 removeEventListener((Container.Listener)bean._bean);
534
535             // stop managed beans
536             if (bean._managed==Managed.MANAGED && bean._bean instanceof LifeCycle)
537             {
538                 try
539                 {
540                     stop((LifeCycle)bean._bean);
541                 }
542                 catch(RuntimeException | Error e)
543                 {
544                     throw e;
545                 }
546                 catch (Exception e)
547                 {
548                     throw new RuntimeException(e);
549                 }
550             }
551             return true;
552         }
553         return false;
554     }
555
556     @Override
557     public void removeEventListener(Container.Listener listener)
558     {
559         if (_listeners.remove(listener))
560         {
561             // remove existing beans
562             for (Bean b:_beans)
563             {
564                 listener.beanRemoved(this,b._bean);
565
566                 if (listener instanceof InheritedListener && b.isManaged() && b._bean instanceof Container)
567                     ((Container)b._bean).removeBean(listener);
568             }
569         }
570     }
571
572     @Override
573     public void setStopTimeout(long stopTimeout)
574     {
575         super.setStopTimeout(stopTimeout);
576         for (Bean bean : _beans)
577         {
578             if (bean.isManaged() && bean._bean instanceof AbstractLifeCycle)
579                 ((AbstractLifeCycle)bean._bean).setStopTimeout(stopTimeout);
580         }
581     }
582
583     /**
584      * Dumps to {@link System#err}.
585      * @see #dump()
586      */
587     @ManagedOperation("Dump the object to stderr")
588     public void dumpStdErr()
589     {
590         try
591         {
592             dump(System.err, "");
593         }
594         catch (IOException e)
595         {
596             LOG.warn(e);
597         }
598     }
599
600     @Override
601     @ManagedOperation("Dump the object to a string")
602     public String dump()
603     {
604         return dump(this);
605     }
606
607     public static String dump(Dumpable dumpable)
608     {
609         StringBuilder b = new StringBuilder();
610         try
611         {
612             dumpable.dump(b, "");
613         }
614         catch (IOException e)
615         {
616             LOG.warn(e);
617         }
618         return b.toString();
619     }
620
621     public void dump(Appendable out) throws IOException
622     {
623         dump(out, "");
624     }
625
626     protected void dumpThis(Appendable out) throws IOException
627     {
628         out.append(String.valueOf(this)).append(" - ").append(getState()).append("\n");
629     }
630
631     public static void dumpObject(Appendable out, Object o) throws IOException
632     {
633         try
634         {
635             if (o instanceof LifeCycle)
636                 out.append(String.valueOf(o)).append(" - ").append((AbstractLifeCycle.getState((LifeCycle)o))).append("\n");
637             else
638                 out.append(String.valueOf(o)).append("\n");
639         }
640         catch (Throwable th)
641         {
642             out.append(" => ").append(th.toString()).append('\n');
643         }
644     }
645
646     @Override
647     public void dump(Appendable out, String indent) throws IOException
648     {
649         dumpBeans(out,indent);
650     }
651
652     protected void dumpBeans(Appendable out, String indent, Collection<?>... collections) throws IOException
653     {
654         dumpThis(out);
655         int size = _beans.size();
656         for (Collection<?> c : collections)
657             size += c.size();
658         if (size == 0)
659             return;
660         int i = 0;
661         for (Bean b : _beans)
662         {
663             i++;
664
665             switch(b._managed)
666             {
667                 case POJO:
668                     out.append(indent).append(" +- ");
669                     if (b._bean instanceof Dumpable)
670                         ((Dumpable)b._bean).dump(out, indent + (i == size ? "    " : " |  "));
671                     else
672                         dumpObject(out, b._bean);
673                     break;
674
675                 case MANAGED:
676                     out.append(indent).append(" += ");
677                     if (b._bean instanceof Dumpable)
678                         ((Dumpable)b._bean).dump(out, indent + (i == size ? "    " : " |  "));
679                     else
680                         dumpObject(out, b._bean);
681                     break;
682
683                 case UNMANAGED:
684                     out.append(indent).append(" +~ ");
685                     dumpObject(out, b._bean);
686                     break;
687
688                 case AUTO:
689                     out.append(indent).append(" +? ");
690                     if (b._bean instanceof Dumpable)
691                         ((Dumpable)b._bean).dump(out, indent + (i == size ? "    " : " |  "));
692                     else
693                         dumpObject(out, b._bean);
694                     break;
695
696             }
697         }
698
699         if (i<size)
700             out.append(indent).append(" |\n");
701
702         for (Collection<?> c : collections)
703         {
704             for (Object o : c)
705             {
706                 i++;
707                 out.append(indent).append(" +> ");
708
709                 if (o instanceof Dumpable)
710                     ((Dumpable)o).dump(out, indent + (i == size ? "    " : " |  "));
711                 else
712                     dumpObject(out, o);
713             }
714         }
715     }
716
717     public static void dump(Appendable out, String indent, Collection<?>... collections) throws IOException
718     {
719         if (collections.length == 0)
720             return;
721         int size = 0;
722         for (Collection<?> c : collections)
723             size += c.size();
724         if (size == 0)
725             return;
726
727         int i = 0;
728         for (Collection<?> c : collections)
729         {
730             for (Object o : c)
731             {
732                 i++;
733                 out.append(indent).append(" +- ");
734
735                 if (o instanceof Dumpable)
736                     ((Dumpable)o).dump(out, indent + (i == size ? "    " : " |  "));
737                 else
738                     dumpObject(out, o);
739             }
740         }
741     }
742
743
744     enum Managed { POJO, MANAGED, UNMANAGED, AUTO };
745
746     private static class Bean
747     {
748         private final Object _bean;
749         private volatile Managed _managed = Managed.POJO;
750
751         private Bean(Object b)
752         {
753             _bean = b;
754         }
755
756         public boolean isManaged()
757         {
758             return _managed==Managed.MANAGED;
759         }
760
761         @Override
762         public String toString()
763         {
764             return String.format("{%s,%s}", _bean, _managed);
765         }
766     }
767
768     public void updateBean(Object oldBean, final Object newBean)
769     {
770         if (newBean!=oldBean)
771         {
772             if (oldBean!=null)
773                 removeBean(oldBean);
774             if (newBean!=null)
775                 addBean(newBean);
776         }
777     }
778
779     public void updateBeans(Object[] oldBeans, final Object[] newBeans)
780     {
781         // remove oldChildren not in newChildren
782         if (oldBeans!=null)
783         {
784             loop: for (Object o:oldBeans)
785             {
786                 if (newBeans!=null)
787                 {
788                     for (Object n:newBeans)
789                         if (o==n)
790                             continue loop;
791                 }
792                 removeBean(o);
793             }
794         }
795
796         // add new beans not in old
797         if (newBeans!=null)
798         {
799             loop: for (Object n:newBeans)
800             {
801                 if (oldBeans!=null)
802                 {
803                     for (Object o:oldBeans)
804                         if (o==n)
805                             continue loop;
806                 }
807                 addBean(n);
808             }
809         }
810     }
811 }