KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icesoft > faces > async > render > RenderManager


1 /*
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * "The contents of this file are subject to the Mozilla Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
11  * License for the specific language governing rights and limitations under
12  * the License.
13  *
14  * The Original Code is ICEfaces 1.5 open source software code, released
15  * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
16  * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
17  * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
18  *
19  * Contributor(s): _____________________.
20  *
21  * Alternatively, the contents of this file may be used under the terms of
22  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
23  * License), in which case the provisions of the LGPL License are
24  * applicable instead of those above. If you wish to allow use of your
25  * version of this file only under the terms of the LGPL License and not to
26  * allow others to use your version of this file under the MPL, indicate
27  * your decision by deleting the provisions above and replace them with
28  * the notice and other provisions required by the LGPL License. If you do
29  * not delete the provisions above, a recipient may use your version of
30  * this file under either the MPL or the LGPL License."
31  *
32  */

33
34 package com.icesoft.faces.async.render;
35
36 import com.icesoft.faces.util.event.servlet.ContextEventRepeater;
37 import edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 import java.util.ArrayList JavaDoc;
42 import java.util.Collections JavaDoc;
43 import java.util.HashMap JavaDoc;
44 import java.util.Iterator JavaDoc;
45 import java.util.Map JavaDoc;
46
47 /**
48  * The RenderManager is the central class for developers wanting to do
49  * server-initiated rendering. The recommended use is to have a single
50  * RenderManager for your application, typically configured as a
51  * application-scope, managed bean. Any class that needs to request server side
52  * render calls can do so using the RenderManager.
53  * <p/>
54  * Server-initiated renders can be requested directly via the {@link
55  * RenderManager#requestRender requestRender} method or you get a named {@link
56  * GroupAsyncRenderer} and add a Renderable implementation to request and
57  * receive render calls as part of a group.
58  * <p/>
59  * The RenderManager contains a reference to a single {@link RenderHub} that
60  * uses a special queue and thread pool to optimize render calls for reliability
61  * and scalability.
62  */

63 public class RenderManager implements Disposable {
64
65     private static Log log = LogFactory.getLog(RenderManager.class);
66
67     static final int MIN = 1;
68     public static final int ON_DEMAND = 2;
69     public static final int INTERVAL = 3;
70     public static final int DELAY = 4;
71     static final int MAX = 4;
72
73     private RenderHub renderHub;
74     private Map JavaDoc groupMap;
75
76     //The ContextEventRepeater stores listeners in a weakly referenced fashion
77
//so we need to hang on to a reference or it will quietly disappear.
78
private ContextDestroyedListener shutdownListener;
79
80     /**
81      * No argument constructor suitable for using as a managed bean.
82      */

83     public RenderManager() {
84         shutdownListener = new ContextDestroyedListener(this);
85         ContextEventRepeater.addListener(shutdownListener);
86         groupMap = Collections.synchronizedMap(new HashMap JavaDoc());
87         renderHub = new RenderHub();
88     }
89
90     /**
91      * Internal utility method that returns the proper type of {@link
92      * GroupAsyncRenderer} and ensures that is added to the managed collection,
93      * indexed by name.
94      *
95      * @param name the unique name of the GroupAsyncRenderer
96      * @param type the type of GroupAsyncRenderer
97      * @return the requested type of GroupAsyncRenderer
98      */

99     private synchronized AsyncRenderer getRenderer(String JavaDoc name, int type) {
100         if (name == null || name.trim().length() == 0) {
101             throw new IllegalArgumentException JavaDoc(
102                     "illegal renderer name: " + name);
103         }
104
105         if (type < MIN || type > MAX) {
106             throw new IllegalArgumentException JavaDoc(
107                     "illegal renderer type: " + type);
108         }
109
110         Object JavaDoc obj = groupMap.get(name);
111         if (obj != null) {
112             if (log.isTraceEnabled()) {
113                 log.trace("existing renderer retrieved: " + name);
114             }
115             return (AsyncRenderer) obj;
116         }
117
118         AsyncRenderer renderer = null;
119         switch (type) {
120             case ON_DEMAND:
121                 renderer = new OnDemandRenderer();
122                 break;
123             case INTERVAL:
124                 renderer = new IntervalRenderer();
125                 break;
126             case DELAY:
127                 renderer = new DelayRenderer();
128                 break;
129         }
130
131         renderer.setName(name);
132         renderer.setRenderManager(this);
133         groupMap.put(name, renderer);
134
135         if (log.isTraceEnabled()) {
136             log.trace("new renderer retrieved: " + name);
137         }
138
139         return renderer;
140     }
141
142     /**
143      * When an AsyncRenderer disposes itself, it also needs to remove itself
144      * from the RenderManager's collection.
145      *
146      * @param renderer The Renderer to remove
147      */

148     protected void removeRenderer(AsyncRenderer renderer) {
149         if (renderer == null) {
150             if (log.isInfoEnabled()) {
151                 log.info("renderer is null");
152             }
153             return;
154         }
155
156         Object JavaDoc removedRenderer = groupMap.remove(renderer.getName());
157         if (removedRenderer == null) {
158             if (log.isTraceEnabled()) {
159                 log.trace("renderer " + renderer.getName() + " not found");
160             }
161         } else {
162             if (log.isTraceEnabled()) {
163                 log.trace("renderer " + renderer.getName() + " removed");
164             }
165         }
166     }
167
168     /**
169      * Submits the supplied Renderable instance to the RenderHub for
170      * server-initiated render.
171      *
172      * @param renderable The {@link Renderable} instance to render.
173      */

174     public void requestRender(Renderable renderable) {
175         renderHub.requestRender(renderable);
176     }
177
178     void relayRender(String JavaDoc rendererName) {
179         //no relay with the standard RenderManaager
180
}
181
182     /**
183      * The OnDemandRenderer is a {@link GroupAsyncRenderer} that requests a
184      * server-initiated render of all the Renderables in its collection. The
185      * request is made immediately upon request.
186      * <p/>
187      * Thsi method returns the appropriate GroupAsyncRenderer based on the name.
188      * If the name is new, a new instance is created and stored in the
189      * RenderManager's collection. If the named GroupAsyncRenderer already
190      * exists, and it's of the proper type, then the existing instance is
191      * returned.
192      *
193      * @param name the name of the GroupAsyncRenderer
194      * @return a new or existing GroupAsyncRenderer, based on the name
195      */

196     public OnDemandRenderer getOnDemandRenderer(String JavaDoc name) {
197         return (OnDemandRenderer) getRenderer(name, ON_DEMAND);
198     }
199
200     /**
201      * The IntervalRenderer is a {@link GroupAsyncRenderer} that requests a
202      * server-initiated render of all the Renderables in its collection. The
203      * request to render is made repeatedly at the set interval.
204      * <p/>
205      * Thsi method returns the appropriate GroupAsyncRenderer based on the name.
206      * If the name is new, a new instance is created and stored in the
207      * RenderManager's collection. If the named GroupAsyncRenderer already
208      * exists, and it's of the proper type, then the existing instance is
209      * returned.
210      *
211      * @param name the name of the GroupAsyncRenderer
212      * @return a new or existing GroupAsyncRenderer, based on the name
213      */

214     public IntervalRenderer getIntervalRenderer(String JavaDoc name) {
215         return (IntervalRenderer) getRenderer(name, INTERVAL);
216     }
217
218     /**
219      * The DelayRenderer is a {@link GroupAsyncRenderer} that requests a
220      * server-initiated render of all the Renderables in its collection. The
221      * request to render is made once at a set point in the future.
222      * <p/>
223      * Thsi method returns the appropriate GroupAsyncRenderer based on the name.
224      * If the name is new, a new instance is created and stored in the
225      * RenderManager's collection. If the named GroupAsyncRenderer already
226      * exists, and it's of the proper type, then the existing instance is
227      * returned.
228      *
229      * @param name the name of the GroupAsyncRenderer
230      * @return a new or existing GroupAsyncRenderer, based on the name
231      */

232     public DelayRenderer getDelayRenderer(String JavaDoc name) {
233         return (DelayRenderer) getRenderer(name, DELAY);
234     }
235
236     /**
237      * This method is used by {@link GroupAsyncRenderer}s that need to request
238      * render calls based on some sort of schedule. It uses a separate,
239      * configurable thread pool and queue than the core rendering service.
240      *
241      * @return the scheduled executor for this RenderManager
242      */

243     ScheduledThreadPoolExecutor getScheduledService() {
244         return renderHub.getScheduledService();
245     }
246
247     /**
248      * This is typically called when the application is shutting down and we
249      * need to dispose of all the RenderManager's resources. It iterates
250      * through all of the named {@link GroupAsyncRenderer}s, calling dispose on
251      * each of them in turn. It then calls dispose on the {@link RenderHub}.
252      * Once the RenderManager has been disposed, it can no longer be used.
253      */

254     public void dispose() {
255         synchronized (groupMap) {
256
257             //Bug 944
258
//We make a copy of the list of renderers to remove simply to
259
//iterate through them. This avoids a concurrent modification
260
//issue when each individual renderers dispose method attempts
261
//to remove itself from the official groupMap.
262
ArrayList JavaDoc renderList = new ArrayList JavaDoc(groupMap.size());
263             renderList.addAll( groupMap.values() );
264             Iterator JavaDoc renderers = renderList.iterator();
265             while (renderers.hasNext()) {
266                 AsyncRenderer renderer = (AsyncRenderer) renderers.next();
267                 renderer.dispose();
268                 if (log.isTraceEnabled()) {
269                     log.trace("renderer disposed: " + renderer);
270                 }
271             }
272             groupMap.clear();
273         }
274         renderHub.dispose();
275         if (log.isDebugEnabled()) {
276             log.debug("all renderers and hub have been disposed");
277         }
278
279     }
280
281     /**
282      * Returns the named instance of an AsyncRenderer if it already exists
283      * otherwise it returns null.
284      *
285      * @param rendererName The name of the AsycRender to retrieve.
286      * @return An instance of an AsyncRenderer that is associated with the
287      * provided name.
288      */

289     public AsyncRenderer getRenderer(String JavaDoc rendererName) {
290         if (rendererName == null) {
291             return null;
292         }
293         return (AsyncRenderer) groupMap.get(rendererName);
294     }
295 }
296
Popular Tags