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.CopyOnWriteArraySet;
037: import org.apache.commons.logging.Log;
038: import org.apache.commons.logging.LogFactory;
039:
040: import java.lang.ref.WeakReference;
041: import java.util.Iterator;
042: import java.util.Set;
043:
044: /**
045: * The GroupAsyncRenderer is the foundation class for other types of renderers
046: * that are designed to operate on a group of {@link Renderable}s. It
047: * implements the {@link AsyncRenderer} interface and is mainly responsible for
048: * smartly managing a group of Renderable instances.
049: * <p/>
050: * Groups of Renderables are stored as WeakReferences in special sets that are
051: * copied before each render pass so that Renderables can be safely added and
052: * removed from the group while a render pass is in progress.
053: * <p/>
054: * Although it is possible to create and use GroupRenderers directly, developers
055: * are advised to use the {@link RenderManager} to create and use named render
056: * groups.
057: *
058: * @author ICEsoft Technologies, Inc.
059: * @see RenderManager, OnDemandRenderer, IntervalRenderer, DelayRenderer
060: */
061: public class GroupAsyncRenderer implements AsyncRenderer {
062:
063: private static Log log = LogFactory
064: .getLog(GroupAsyncRenderer.class);
065:
066: protected String name;
067: protected Set group;
068: protected RenderManager renderManager;
069:
070: protected boolean stopRequested = false;
071:
072: public GroupAsyncRenderer() {
073: group = new CopyOnWriteArraySet();
074: }
075:
076: public String getName() {
077: return name;
078: }
079:
080: public void setName(String name) {
081: this .name = name;
082: }
083:
084: public void setRenderManager(RenderManager renderManager) {
085: this .renderManager = renderManager;
086: }
087:
088: /**
089: * Adds a Renderable, via a WeakReference, to the set of Renderables of this
090: * group. If the Renderable is already in this set, it is not added again.
091: *
092: * @param renderable the Renderable instance to add to the group.
093: */
094: public void add(Renderable renderable) {
095: synchronized (group) {
096: if (!contains(renderable)) {
097: if (group.add(new WeakReference(renderable))) {
098: if (log.isTraceEnabled()) {
099: log.trace(name + " added " + renderable);
100: }
101: } else {
102: if (log.isWarnEnabled()) {
103: log.warn(name + " already contains "
104: + renderable);
105: }
106: }
107: }
108: }
109: }
110:
111: public boolean contains(Renderable renderable) {
112: Iterator iter = group.iterator();
113: while (iter.hasNext()) {
114: if (renderable == (Renderable) ((WeakReference) iter.next())
115: .get()) {
116: return true;
117: }
118: }
119: return false;
120: }
121:
122: /**
123: * Removes a Renderable, via a WeakReference, from the set of Renderables of
124: * this group.
125: *
126: * @param renderable the Renderable instance to remove
127: */
128: public void remove(Renderable renderable) {
129: synchronized (group) {
130: Iterator iter = group.iterator();
131: while (iter.hasNext()) {
132: WeakReference ref = (WeakReference) iter.next();
133: if (renderable == (Renderable) ref.get()) {
134: group.remove(ref);
135: if (log.isTraceEnabled()) {
136: log.trace(name + " removing " + renderable);
137: }
138: return;
139: }
140: }
141: if (log.isWarnEnabled()) {
142: log.warn(name + " does not contain " + renderable);
143: }
144: }
145: }
146:
147: /**
148: * Removes all Renderables from the group.
149: */
150: public void clear() {
151: synchronized (group) {
152: group.clear();
153: }
154: }
155:
156: /**
157: * Used to determine if the Renderer has any Renderables left in its
158: * collection.
159: *
160: * @return false if there are 1 or more Renderables left in the Renderer's
161: * collection, true otherwise
162: */
163: public boolean isEmpty() {
164: return group.isEmpty();
165: }
166:
167: /**
168: * Request a render pass on all the Renderables in the group. Render calls
169: * that generate exceptions are passed back to the Renderable.renderException
170: *
171: * @throws IllegalStateException If a reference to a {@link RenderHub} has
172: * not yet been set.
173: */
174: public void requestRender() {
175: if (renderManager == null) {
176: String message = "RenderManager has not been set";
177: if (log.isErrorEnabled()) {
178: log.error(message);
179: }
180: throw new IllegalStateException(message);
181:
182: }
183:
184: Iterator iter = group.iterator();
185: if (log.isTraceEnabled()) {
186: log.trace(name + " preparing to render " + group.size());
187: }
188:
189: stopRequested = false;
190: while (iter.hasNext() && !stopRequested) {
191: Renderable renderable = (Renderable) ((WeakReference) iter
192: .next()).get();
193: renderManager.requestRender(renderable);
194: }
195: }
196:
197: /**
198: * The method called by dispose to halt a render pass at the current {@link
199: * Renderable}s.
200: */
201: public void requestStop() {
202: stopRequested = true;
203: }
204:
205: /**
206: * Remove all Renderables from the group and removes the reference to the
207: * RenderHub. Once disposed, a GroupAsyncRenderer cannot be re-used. This
208: * method is typically used by the RenderManager to cleanly dispose of all
209: * managed Renderers when the application is shutting down.
210: */
211: public void dispose() {
212: requestStop();
213: group.clear();
214: group = null;
215: renderManager.removeRenderer(this);
216: name = null;
217: renderManager = null;
218: }
219: }
|