001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033:
034: package com.icesoft.faces.async.render;
035:
036: import edu.emory.mathcs.backport.java.util.concurrent.ScheduledThreadPoolExecutor;
037: import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
038: import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041:
042: /**
043: * The RenderHub is designed to handle all server-side rendering calls. Although
044: * it can be created programmatically, it is recommended that the application
045: * developer use a {@link RenderManager} instance for all rendering duties and
046: * for creating named {@link GroupAsyncRenderer)s. The RenderManager creates
047: * and uses its own RenderHub for all rendering.
048: * <p/>
049: * A single RenderHub should handle all server-side rendering duties in a
050: * thread-safe and efficient manner. It uses a specialized queue to hold {@link
051: * Renderable} instances and a thread pool to render each Renderable on the
052: * queue. The queue will only keep a single entry of any particular Renderable.
053: * Subsequent Renderables that are offered to the queue for rendering are
054: * discarded since any pending render call will update the client to the latest
055: * state. This coalescing of render calls makes it safer and more efficient for
056: * the application developer to add rendering into their application.
057: *
058: * @author ICEsoft Technologies, Inc.
059: * @see RenderManager
060: */
061: public class RenderHub {
062:
063: private static Log log = LogFactory.getLog(RenderHub.class);
064:
065: /**
066: * The specialized thread pool used to execute render calls on Renderable
067: * instances. It uses the supplied settings for defaults.
068: */
069: private ThreadPoolExecutor renderService;
070: private int corePoolSize = 10;
071: private int maxPoolSize = 15;
072: private long keepAliveTime = 300000;
073: private int renderQueueCapacity = 1000;
074:
075: /**
076: * The specialized thread pool used to execute render calls at some future
077: * time. The RenderHub makes this available to Renderers that need this
078: * ability.
079: *
080: * @see IntervalRenderer, DelayRenderer
081: */
082: private ScheduledThreadPoolExecutor scheduledService;
083: private int schedulePoolSize = 5;
084:
085: /**
086: * Used by the ThreadPoolExector as a callback for rejected Runnable
087: * executions.
088: */
089: private RejectionHandler rejectionHandler;
090:
091: /**
092: * Used by the ThreadPoolExecutor to create its thread pool.
093: */
094: private RenderThreadFactory threadFactory;
095:
096: /**
097: * Public constructor. Although it possible for developers to construct and
098: * use their own RenderHub, it is highly recommended that a RenderManager be
099: * used. The RenderManager creates and uses it's own internal RenderHub.
100: */
101: public RenderHub() {
102: rejectionHandler = new RejectionHandler();
103: threadFactory = new RenderThreadFactory();
104: }
105:
106: /**
107: * Get the starting size of the core thread pool.
108: *
109: * @return The starting size of the core thread pool.
110: */
111: public int getCorePoolSize() {
112: return corePoolSize;
113: }
114:
115: /**
116: * Set the thread pool size of the core render service. The default is 10.
117: * This number will need to be adjusted based on the characteristics of the
118: * application. Note that increasing the number of threads past a certain
119: * number (based on OS, JVM, etc) can actually decrease performance as
120: * thread context switching becomes a burden.
121: *
122: * @param corePoolSize The number of threads to dedicate to the scheduled
123: * service thread pool.
124: */
125: public void setCorePoolSize(int corePoolSize) {
126: this .corePoolSize = corePoolSize;
127: }
128:
129: /**
130: * Get the maximum size of the core thread pool.
131: *
132: * @return The maximum size of the core thread pool.
133: */
134: public int getMaxPoolSize() {
135: return maxPoolSize;
136: }
137:
138: /**
139: * Set the maximum thread pool size of the core render service. The default
140: * is 15. This number will need to be adjusted based on the characteristics
141: * of the application. Note that increasing the number of threads past a
142: * certain number (based on OS, JVM, etc) can actually decrease performance
143: * as thread context switching becomes a burden.
144: *
145: * @param maxPoolSize The maximum number of threads to dedicate to the core
146: * service thread pool.
147: */
148: public void setMaxPoolSize(int maxPoolSize) {
149: this .maxPoolSize = maxPoolSize;
150: }
151:
152: /**
153: * Get the keep alive time of threads above the core number. The number of
154: * threads that are created past the core number (up to the maximum number)
155: * are kept alive until they are idle for the keep alive time.
156: *
157: * @return The keep alive time for threads created past the core number.
158: */
159: public long getKeepAliveTime() {
160: return keepAliveTime;
161: }
162:
163: /**
164: * Set the amount of idle time to keep threads created above the core size.
165: * The default is 300000 ms.
166: *
167: * @param keepAliveTime The idle time in ms to keep additional threads
168: * alive.
169: */
170: public void setKeepAliveTime(long keepAliveTime) {
171: this .keepAliveTime = keepAliveTime;
172: }
173:
174: /**
175: * Get the capacity of the core render service queue.
176: *
177: * @return The capacity of the core render service queue.
178: */
179: public int getRenderQueueCapacity() {
180: return renderQueueCapacity;
181: }
182:
183: public void setRenderQueueCapacity(int renderQueueCapacity) {
184: this .renderQueueCapacity = renderQueueCapacity;
185: }
186:
187: /**
188: * The prime responsibility of the RenderHub is to perform a render call on
189: * the submitted Renderable. Each call to this method is submitted and, if
190: * not already in the queue, placed on the queue to be rendered. The thread
191: * pool is created here if does not yet exist using whatever configuration
192: * values have been set.
193: *
194: * @param renderable The Renderable instance to add to the rendering queue.
195: */
196: public void requestRender(Renderable renderable) {
197: if (renderService == null) {
198: createCoreService();
199: }
200: renderService.execute(new RunnableRender(renderable));
201: }
202:
203: /**
204: * Method for creating the thread pool/queue service. Currently we use a
205: * JDK 1.4.x backport of the JDK 1.5.x concurrency utilities.
206: */
207: private synchronized void createCoreService() {
208:
209: SingleEntryQueue queue = new SingleEntryQueue(
210: renderQueueCapacity);
211:
212: renderService = new ThreadPoolExecutor(corePoolSize,
213: maxPoolSize, keepAliveTime, TimeUnit.MILLISECONDS,
214: queue, threadFactory, rejectionHandler);
215:
216: if (log.isInfoEnabled()) {
217: log.info("core render service created:"
218: + "\n core pool size : " + corePoolSize
219: + "\n max pool size : " + maxPoolSize
220: + "\n keep alive time: " + keepAliveTime);
221: }
222: }
223:
224: /**
225: * As a secondary responsibility, the RenderHub also maintains a thread pool
226: * for render calls that should occur in the future. This service is used
227: * by renderers such as the {@link IntervalRenderer} and {@link
228: * DelayRenderer} to delay the eventual render calls. All the rendering is
229: * still handled by the RenderHubs core thread pool/queue. The scheduled
230: * service is used to delay when that occurs. Having this supplied by the
231: * RenderHub ensures that there is only one.
232: *
233: * @return A scheduling service.
234: */
235: public ScheduledThreadPoolExecutor getScheduledService() {
236: if (scheduledService == null) {
237: createScheduledService();
238: }
239: return scheduledService;
240: }
241:
242: protected synchronized void createScheduledService() {
243:
244: scheduledService = new ScheduledThreadPoolExecutor(
245: corePoolSize, threadFactory, rejectionHandler);
246: if (log.isInfoEnabled()) {
247: log.info("scheduled render service created:"
248: + "\n core pool size : " + schedulePoolSize);
249: }
250: }
251:
252: /**
253: * Get the thread pool size of the scheduled render service.
254: *
255: * @return the size of the schedule service thread pool
256: */
257: public int getSchedulePoolSize() {
258: return schedulePoolSize;
259: }
260:
261: /**
262: * Set the thread pool size of the scheduled render service. The default is
263: * 5 and unless you have a lot of renderers that use the scheduling service,
264: * it should really be more than enough.
265: *
266: * @param schedulePoolSize The number of threads to dedicate to the
267: * scheduled service thread pool.
268: */
269: public void setSchedulePoolSize(int schedulePoolSize) {
270: this .schedulePoolSize = schedulePoolSize;
271: }
272:
273: /**
274: * Cleanly disposes of the RenderHub's resources. Used by the RenderManager
275: * when the application shuts down.
276: */
277: public void dispose() {
278: if (renderService != null) {
279: renderService.shutdown();
280: renderService = null;
281: }
282:
283: if (scheduledService != null) {
284: scheduledService.shutdown();
285: scheduledService = null;
286: }
287: }
288: }
|