001: /* Copyright 2001, 2005 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.services.stats;
007:
008: import org.apache.commons.logging.Log;
009: import org.apache.commons.logging.LogFactory;
010: import org.jasig.portal.ChannelDefinition;
011: import org.jasig.portal.PortalSessionManager;
012: import org.jasig.portal.UserProfile;
013: import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
014: import org.jasig.portal.layout.node.IUserLayoutFolderDescription;
015: import org.jasig.portal.security.IPerson;
016: import org.jasig.portal.utils.threading.PriorityThreadFactory;
017: import org.springframework.beans.factory.InitializingBean;
018:
019: import edu.emory.mathcs.backport.java.util.concurrent.ExecutorService;
020: import edu.emory.mathcs.backport.java.util.concurrent.LinkedBlockingQueue;
021: import edu.emory.mathcs.backport.java.util.concurrent.ThreadPoolExecutor;
022: import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
023:
024: /**
025: * Stats recorder implementation which on receipt of each stats recording event
026: * fires a new thread tasked with notifying the child recorder of the event. This
027: * accomplishes processing stats recording in a new thread rather than in
028: * the thread in which the event was generated.
029: *
030: * This IStatsRecorder just fires the threads - it requires a target IStatsRecorder
031: * which the threads will invoke. You inject this target via the setTargetStatsRecorder()
032: * setter method.
033: *
034: * @version $Revision: 36731 $ $Date: 2006-09-27 11:21:06 -0700 (Wed, 27 Sep 2006) $
035: *
036: * @deprecated IStatsRecorder implementation is replaced with a much more flexible system
037: * based on the Spring ApplicationEventPublisher and Event Listeners.
038: * For more information see:
039: * http://www.ja-sig.org/wiki/display/UPC/Proposal+to+Deprecate+IStatsRecorder
040: */
041: public final class ThreadFiringStatsRecorder implements IStatsRecorder,
042: InitializingBean {
043:
044: private Log log = LogFactory.getLog(getClass());
045:
046: private IStatsRecorder targetStatsRecorder;
047:
048: private ExecutorService threadPool;
049:
050: /**
051: * Constructor specifying configurating of our thread pool.
052: * @param initialThreads initial number of threads in the thread pool
053: * @param maxThreads maximum number of threads to allow in the thread pool
054: * @param threadPriority priority for the threads.
055: */
056: public ThreadFiringStatsRecorder(int initialThreads,
057: int maxThreads, int threadPriority) {
058: this .threadPool = new ThreadPoolExecutor(initialThreads,
059: maxThreads, 0L, TimeUnit.MILLISECONDS,
060: new LinkedBlockingQueue(), new PriorityThreadFactory(
061: threadPriority, "Stats Recorder",
062: PortalSessionManager.getThreadGroup()));
063: }
064:
065: public void recordLogin(IPerson person) {
066: StatsRecorderWorkerTask task = new RecordLoginWorkerTask(person);
067: executeStatsRecorderEvent(task);
068: }
069:
070: public void recordLogout(IPerson person) {
071: StatsRecorderWorkerTask task = new RecordLogoutWorkerTask(
072: person);
073: executeStatsRecorderEvent(task);
074: }
075:
076: public void recordSessionCreated(IPerson person) {
077: StatsRecorderWorkerTask task = new RecordSessionCreatedWorkerTask(
078: person);
079: executeStatsRecorderEvent(task);
080: }
081:
082: public void recordSessionDestroyed(IPerson person) {
083: StatsRecorderWorkerTask task = new RecordSessionDestroyedWorkerTask(
084: person);
085: executeStatsRecorderEvent(task);
086: }
087:
088: public void recordChannelDefinitionPublished(IPerson person,
089: ChannelDefinition channelDef) {
090: StatsRecorderWorkerTask task = new RecordChannelDefinitionPublishedWorkerTask(
091: person, channelDef);
092: executeStatsRecorderEvent(task);
093: }
094:
095: public void recordChannelDefinitionModified(IPerson person,
096: ChannelDefinition channelDef) {
097: StatsRecorderWorkerTask task = new RecordChannelDefinitionModifiedWorkerTask(
098: person, channelDef);
099: executeStatsRecorderEvent(task);
100: }
101:
102: public void recordChannelDefinitionRemoved(IPerson person,
103: ChannelDefinition channelDef) {
104: StatsRecorderWorkerTask task = new RecordChannelDefinitionRemovedWorkerTask(
105: person, channelDef);
106: executeStatsRecorderEvent(task);
107: }
108:
109: public void recordChannelAddedToLayout(IPerson person,
110: UserProfile profile,
111: IUserLayoutChannelDescription channelDesc) {
112: StatsRecorderWorkerTask task = new RecordChannelAddedToLayoutWorkerTask(
113: person, profile, channelDesc);
114: executeStatsRecorderEvent(task);
115: }
116:
117: public void recordChannelUpdatedInLayout(IPerson person,
118: UserProfile profile,
119: IUserLayoutChannelDescription channelDesc) {
120: StatsRecorderWorkerTask task = new RecordChannelUpdatedInLayoutWorkerTask(
121: person, profile, channelDesc);
122: executeStatsRecorderEvent(task);
123: }
124:
125: public void recordChannelMovedInLayout(IPerson person,
126: UserProfile profile,
127: IUserLayoutChannelDescription channelDesc) {
128: StatsRecorderWorkerTask task = new RecordChannelMovedInLayoutWorkerTask(
129: person, profile, channelDesc);
130: executeStatsRecorderEvent(task);
131: }
132:
133: public void recordChannelRemovedFromLayout(IPerson person,
134: UserProfile profile,
135: IUserLayoutChannelDescription channelDesc) {
136: StatsRecorderWorkerTask task = new RecordChannelRemovedFromLayoutWorkerTask(
137: person, profile, channelDesc);
138: executeStatsRecorderEvent(task);
139: }
140:
141: public void recordFolderAddedToLayout(IPerson person,
142: UserProfile profile, IUserLayoutFolderDescription folderDesc) {
143: StatsRecorderWorkerTask task = new RecordFolderAddedToLayoutWorkerTask(
144: person, profile, folderDesc);
145: executeStatsRecorderEvent(task);
146: }
147:
148: public void recordFolderUpdatedInLayout(IPerson person,
149: UserProfile profile, IUserLayoutFolderDescription folderDesc) {
150: StatsRecorderWorkerTask task = new RecordFolderUpdatedInLayoutWorkerTask(
151: person, profile, folderDesc);
152: executeStatsRecorderEvent(task);
153: }
154:
155: public void recordFolderMovedInLayout(IPerson person,
156: UserProfile profile, IUserLayoutFolderDescription folderDesc) {
157: StatsRecorderWorkerTask task = new RecordFolderMovedInLayoutWorkerTask(
158: person, profile, folderDesc);
159: executeStatsRecorderEvent(task);
160: }
161:
162: public void recordFolderRemovedFromLayout(IPerson person,
163: UserProfile profile, IUserLayoutFolderDescription folderDesc) {
164: StatsRecorderWorkerTask task = new RecordFolderRemovedFromLayoutWorkerTask(
165: person, profile, folderDesc);
166: executeStatsRecorderEvent(task);
167: }
168:
169: public void recordChannelInstantiated(IPerson person,
170: UserProfile profile,
171: IUserLayoutChannelDescription channelDesc) {
172: StatsRecorderWorkerTask task = new RecordChannelInstantiatedWorkerTask(
173: person, profile, channelDesc);
174: executeStatsRecorderEvent(task);
175: }
176:
177: public void recordChannelRendered(IPerson person,
178: UserProfile profile,
179: IUserLayoutChannelDescription channelDesc) {
180: StatsRecorderWorkerTask task = new RecordChannelRenderedWorkerTask(
181: person, profile, channelDesc);
182: executeStatsRecorderEvent(task);
183: }
184:
185: public void recordChannelTargeted(IPerson person,
186: UserProfile profile,
187: IUserLayoutChannelDescription channelDesc) {
188: StatsRecorderWorkerTask task = new RecordChannelTargetedWorkerTask(
189: person, profile, channelDesc);
190: executeStatsRecorderEvent(task);
191: }
192:
193: private void executeStatsRecorderEvent(
194: final StatsRecorderWorkerTask task) {
195: // local defensive copy so that even if someone calls our setter method during
196: // this method invocation, we will check for null
197: IStatsRecorder delegateStatsRecorder = this .targetStatsRecorder;
198:
199: if (delegateStatsRecorder == null) {
200: // log the illegal state and do nothing
201: // we do not throw an exception because we don't want a statistics
202: // recording problem to propogate out into more important portal components.
203: log
204: .error("targetStatsRecorder JavaBean property of ThreadFiringStatsRecorder illegally null.");
205: } else {
206: task.setStatsRecorder(this .targetStatsRecorder);
207: this .threadPool.execute(task); // TODO is execute okay or should it be submit?
208: }
209: }
210:
211: /**
212: * Get the target IStatsRecorder which the threads we fire will invoke when they
213: * awake.
214: * @return Returns the targetStatsRecorder.
215: */
216: public IStatsRecorder getTargetStatsRecorder() {
217: return this .targetStatsRecorder;
218: }
219:
220: /**
221: * Set the child IStatsRecorder which the threads we fire will invoke when they
222: * awake.
223: * @param targetStatsRecorder The targetStatsRecorder to set.
224: */
225: public void setTargetStatsRecorder(
226: IStatsRecorder targetStatsRecorder) {
227:
228: if (targetStatsRecorder == null) {
229: throw new IllegalArgumentException(
230: "Cannot set targetStatsRecorder to null");
231: }
232:
233: this .targetStatsRecorder = targetStatsRecorder;
234: }
235:
236: public void afterPropertiesSet() throws Exception {
237: // we implement this Spring beanfactory lifecycle interface method so that
238: // when an instance of this class is configured using Spring, we
239: // take the opportunity to check that our required JavaBean property
240: // has been set
241: if (this .targetStatsRecorder == null) {
242: throw new IllegalStateException(
243: "ThreadFiringStatsRecorder requires that the targetStatsRecorder be set.");
244: }
245: }
246: }
|