View Javadoc
1   package org.apache.commons.jcs.engine.control.event;
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.IOException;
23  import java.util.concurrent.LinkedBlockingQueue;
24  import java.util.concurrent.ThreadPoolExecutor;
25  import java.util.concurrent.TimeUnit;
26  
27  import org.apache.commons.jcs.engine.control.event.behavior.IElementEvent;
28  import org.apache.commons.jcs.engine.control.event.behavior.IElementEventHandler;
29  import org.apache.commons.jcs.engine.control.event.behavior.IElementEventQueue;
30  import org.apache.commons.jcs.utils.threadpool.DaemonThreadFactory;
31  import org.apache.commons.logging.Log;
32  import org.apache.commons.logging.LogFactory;
33  
34  /**
35   * An event queue is used to propagate ordered cache events to one and only one target listener.
36   */
37  public class ElementEventQueue
38      implements IElementEventQueue
39  {
40      private static final String THREAD_PREFIX = "JCS-ElementEventQueue-";
41  
42      /** The logger */
43      private static final Log log = LogFactory.getLog( ElementEventQueue.class );
44  
45      /** shutdown or not */
46      private boolean destroyed = false;
47  
48      /** The event queue */
49      private LinkedBlockingQueue<Runnable> queue;
50  
51      /** The worker thread pool. */
52      private ThreadPoolExecutor queueProcessor;
53  
54      /**
55       * Constructor for the ElementEventQueue object
56       */
57      public ElementEventQueue()
58      {
59          queue = new LinkedBlockingQueue<Runnable>();
60          queueProcessor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS,
61                  queue, new DaemonThreadFactory(THREAD_PREFIX));
62  
63          if ( log.isDebugEnabled() )
64          {
65              log.debug( "Constructed: " + this );
66          }
67      }
68  
69      /**
70       * Dispose queue
71       */
72      @Override
73      public void dispose()
74      {
75          if ( !destroyed )
76          {
77              destroyed = true;
78  
79              // synchronize on queue so the thread will not wait forever,
80              // and then interrupt the QueueProcessor
81              queueProcessor.shutdownNow();
82              queueProcessor = null;
83  
84              if ( log.isInfoEnabled() )
85              {
86                  log.info( "Element event queue destroyed: " + this );
87              }
88          }
89      }
90  
91      /**
92       * Adds an ElementEvent to be handled
93       * @param hand The IElementEventHandler
94       * @param event The IElementEventHandler IElementEvent event
95       * @throws IOException
96       */
97      @Override
98      public <T> void addElementEvent( IElementEventHandler hand, IElementEvent<T> event )
99          throws IOException
100     {
101 
102         if ( log.isDebugEnabled() )
103         {
104             log.debug( "Adding Event Handler to QUEUE, !destroyed = " + !destroyed );
105         }
106 
107         if (destroyed)
108         {
109             log.warn("Event submitted to disposed element event queue " + event);
110         }
111         else
112         {
113             ElementEventRunner runner = new ElementEventRunner( hand, event );
114 
115             if ( log.isDebugEnabled() )
116             {
117                 log.debug( "runner = " + runner );
118             }
119 
120             queueProcessor.execute(runner);
121         }
122     }
123 
124     // /////////////////////////// Inner classes /////////////////////////////
125 
126     /**
127      * Retries before declaring failure.
128      */
129     protected abstract class AbstractElementEventRunner
130         implements Runnable
131     {
132         /**
133          * Main processing method for the AbstractElementEvent object
134          */
135         @SuppressWarnings("synthetic-access")
136         @Override
137         public void run()
138         {
139             try
140             {
141                 doRun();
142                 // happy and done.
143             }
144             catch ( IOException e )
145             {
146                 // Too bad. The handler has problems.
147                 log.warn( "Giving up element event handling " + ElementEventQueue.this, e );
148             }
149         }
150 
151         /**
152          * This will do the work or trigger the work to be done.
153          * <p>
154          * @throws IOException
155          */
156         protected abstract void doRun()
157             throws IOException;
158     }
159 
160     /**
161      * ElementEventRunner.
162      */
163     private class ElementEventRunner
164         extends AbstractElementEventRunner
165     {
166         /** the handler */
167         private final IElementEventHandler hand;
168 
169         /** event */
170         private final IElementEvent<?> event;
171 
172         /**
173          * Constructor for the PutEvent object.
174          * <p>
175          * @param hand
176          * @param event
177          * @throws IOException
178          */
179         @SuppressWarnings("synthetic-access")
180         ElementEventRunner( IElementEventHandler hand, IElementEvent<?> event )
181             throws IOException
182         {
183             if ( log.isDebugEnabled() )
184             {
185                 log.debug( "Constructing " + this );
186             }
187             this.hand = hand;
188             this.event = event;
189         }
190 
191         /**
192          * Tells the handler to handle the event.
193          * <p>
194          * @throws IOException
195          */
196         @Override
197         protected void doRun()
198             throws IOException
199         {
200             hand.handleElementEvent( event );
201         }
202     }
203 }