/**
* Copyright © 2002 The JA-SIG Collaborative. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. Redistributions of any form whatsoever must retain the following
* acknowledgment:
* "This product includes software developed by the JA-SIG Collaborative
* (http://www.jasig.org/)."
*
* THIS SOFTWARE IS PROVIDED BY THE JA-SIG COLLABORATIVE "AS IS" AND ANY
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE JA-SIG COLLABORATIVE OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.jasig.portal.services;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portal.ChannelDefinition;
import org.jasig.portal.UserProfile;
import org.jasig.portal.car.CarResources;
import org.jasig.portal.layout.IUserLayoutChannelDescription;
import org.jasig.portal.layout.IUserLayoutFolderDescription;
import org.jasig.portal.properties.PropertiesManager;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.services.stats.DoNothingStatsRecorderFactory;
import org.jasig.portal.services.stats.IStatsRecorder;
import org.jasig.portal.services.stats.IStatsRecorderFactory;
import org.jasig.portal.services.stats.RecordChannelAddedToLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordChannelDefinitionModifiedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelDefinitionPublishedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelDefinitionRemovedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelInstantiatedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelMovedInLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordChannelRemovedFromLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordChannelRenderedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelTargetedWorkerTask;
import org.jasig.portal.services.stats.RecordChannelUpdatedInLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordFolderAddedToLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordFolderMovedInLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordFolderRemovedFromLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordFolderUpdatedInLayoutWorkerTask;
import org.jasig.portal.services.stats.RecordLoginWorkerTask;
import org.jasig.portal.services.stats.RecordLogoutWorkerTask;
import org.jasig.portal.services.stats.RecordSessionCreatedWorkerTask;
import org.jasig.portal.services.stats.RecordSessionDestroyedWorkerTask;
import org.jasig.portal.services.stats.SaveRDBMStatisticsWorkerTask;
import org.jasig.portal.services.stats.StatsRecorderLayoutEventListener;
import org.jasig.portal.services.stats.StatsRecorderSettings;
import org.jasig.portal.services.stats.StatsRecorderWorkerTask;
import org.jasig.portal.utils.threading.BoundedThreadPool;
import org.jasig.portal.utils.threading.ThreadPool;
import org.jasig.portal.utils.threading.WorkTracker;
/**
* Stats recorder service. Various parts of the portal call
* the methods in this service to record events such as
* when a user logs in, logs out, and subscribes to a channel.
* The information is handed off in a separate thread
* to an IStatsRecorder implementation that is determined
* by the IStatsRecorderFactory implementation that can be
* configured in portal.properties.
* @author Ken Weiner, kweiner@unicon.net
* @author rtwigg@uccs.edu
* @version $Revision: 1.15.2.1 $
*/
public class StatsRecorder {
private static final Log log = LogFactory.getLog(StatsRecorder.class);
protected static StatsRecorder statsRecorderInstance;
protected StatsRecorderSettings statsRecorderSettings;
protected IStatsRecorder statsRecorder;
protected ThreadPool threadPool;
/**
* Constructor with private access so that the StatsRecorder
* maintains only one instance of itself.
*/
private StatsRecorder() {
String statsRecorderFactoryName = null;
IStatsRecorderFactory statsRecorderFactory = null;
try {
// Get a stats recorder from the stats recorder factory.
statsRecorderFactoryName = PropertiesManager.getProperty("org.jasig.portal.services.stats.StatsRecorderFactory.implementation");
statsRecorderFactory = (IStatsRecorderFactory)CarResources.getInstance().getClassLoader().loadClass(statsRecorderFactoryName).newInstance();
} catch (Exception e) {
log.error( "Unable to instantiate stats recorder '" + statsRecorderFactoryName + "'. Continuing with DoNothingStatsRecorder.", e);
statsRecorderFactory = new DoNothingStatsRecorderFactory();
}
try {
statsRecorder = statsRecorderFactory.getStatsRecorder();
// Get the stats recorder settings instance
statsRecorderSettings = StatsRecorderSettings.instance();
// Create a thread pool
String prefix = this.getClass().getName() + ".threadPool_";
int initialThreads = PropertiesManager.getPropertyAsInt(prefix + "initialThreads");
int maxThreads = PropertiesManager.getPropertyAsInt(prefix + "maxThreads");
int threadPriority = PropertiesManager.getPropertyAsInt(prefix + "threadPriority");
threadPool = new BoundedThreadPool(initialThreads, maxThreads, threadPriority);
} catch (Exception e) {
log.error("Error instantiating StatsRecorder", e);
}
}
/**
* Creates an instance of this stats recorder service.
* @return a StatsRecorder
* instance
*/
private final static synchronized StatsRecorder instance() {
if (statsRecorderInstance == null) {
statsRecorderInstance = new StatsRecorder();
}
return statsRecorderInstance;
}
/**
* Creates an instance of a
* StatsRecorderLayoutEventListener
.
* @return a new stats recorder layout event listener instance
*/
public final static StatsRecorderLayoutEventListener newLayoutEventListener(IPerson person, UserProfile profile) {
return new StatsRecorderLayoutEventListener(person, profile);
}
/**
* Gets the value of a particular stats recorder setting.
* Possible settings are available from StatsRecorderSettings
.
* For example: StatsRecorder.get(StatsRecorderSettings.RECORD_LOGIN)
* @param setting the setting
* @return the value for the setting
*/
public static boolean get(int setting) {
return instance().statsRecorderSettings.get(setting);
}
/**
* Sets the value of a particular stats recorder setting.
* Possible settings are available from StatsRecorderSettings
.
* For example: StatsRecorder.set(StatsRecorderSettings.RECORD_LOGIN, true)
* @param setting the setting to change
* @param newValue the new value for the setting
*/
public static void set(int setting, boolean newValue) {
instance().statsRecorderSettings.set(setting, newValue);
}
/**
* Record the successful login of a user.
* @param person the person who is logging in
*/
public static void recordLogin(IPerson person) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_LOGIN)) {
StatsRecorderWorkerTask task = new RecordLoginWorkerTask(person);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record the logout of a user.
* @param person the person who is logging out
*/
public static void recordLogout(IPerson person) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_LOGOUT)) {
StatsRecorderWorkerTask task = new RecordLogoutWorkerTask(person);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a new session is created for a user.
* @param person the person whose session is being created
*/
public static void recordSessionCreated(IPerson person) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_SESSION_CREATED)) {
StatsRecorderWorkerTask task = new RecordSessionCreatedWorkerTask(person);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a user's session is destroyed
* (when the user logs out or his/her session
* simply times out)
* @param person the person whose session is ending
*/
public static void recordSessionDestroyed(IPerson person) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_SESSION_DESTROYED)) {
StatsRecorderWorkerTask task = new RecordSessionDestroyedWorkerTask(person);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a new channel is being published
* @param person the person publishing the channel
* @param channelDef the channel being published
*/
public static void recordChannelDefinitionPublished(IPerson person, ChannelDefinition channelDef) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_DEFINITION_PUBLISHED)) {
StatsRecorderWorkerTask task = new RecordChannelDefinitionPublishedWorkerTask(person, channelDef);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that an existing channel is being modified
* @param person the person modifying the channel
* @param channelDef the channel being modified
*/
public static void recordChannelDefinitionModified(IPerson person, ChannelDefinition channelDef) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_DEFINITION_MODIFIED)) {
StatsRecorderWorkerTask task = new RecordChannelDefinitionModifiedWorkerTask(person, channelDef);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being removed
* @param person the person removing the channel
* @param channelDef the channel being modified
*/
public static void recordChannelDefinitionRemoved(IPerson person, ChannelDefinition channelDef) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_DEFINITION_REMOVED)) {
StatsRecorderWorkerTask task = new RecordChannelDefinitionRemovedWorkerTask(person, channelDef);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being added to a user layout
* @param person the person adding the channel
* @param profile the profile of the layout to which the channel is being added
* @param channelDesc the channel being subscribed to
*/
public static void recordChannelAddedToLayout(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_ADDED_TO_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordChannelAddedToLayoutWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being updated in a user layout
* @param person the person updating the channel
* @param profile the profile of the layout in which the channel is being updated
* @param channelDesc the channel being updated
*/
public static void recordChannelUpdatedInLayout(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_UPDATED_IN_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordChannelUpdatedInLayoutWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being moved in a user layout
* @param person the person moving the channel
* @param profile the profile of the layout in which the channel is being moved
* @param channelDesc the channel being moved
*/
public static void recordChannelMovedInLayout(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_MOVED_IN_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordChannelMovedInLayoutWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being removed from a user layout
* @param person the person removing the channel
* @param profile the profile of the layout to which the channel is being added
* @param channelDesc the channel being removed from a user layout
*/
public static void recordChannelRemovedFromLayout(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_REMOVED_FROM_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordChannelRemovedFromLayoutWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a folder is being added to a user layout
* @param person the person adding the folder
* @param profile the profile of the layout to which the folder is being added
* @param folderDesc the folder being subscribed to
*/
public static void recordFolderAddedToLayout(IPerson person, UserProfile profile, IUserLayoutFolderDescription folderDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_FOLDER_ADDED_TO_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordFolderAddedToLayoutWorkerTask(person, profile, folderDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a folder is being updated in a user layout
* @param person the person updating the folder
* @param profile the profile of the layout in which the folder is being updated
* @param folderDesc the folder being updated
*/
public static void recordFolderUpdatedInLayout(IPerson person, UserProfile profile, IUserLayoutFolderDescription folderDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_FOLDER_UPDATED_IN_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordFolderUpdatedInLayoutWorkerTask(person, profile, folderDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a folder is being moved in a user layout
* @param person the person moving the folder
* @param profile the profile of the layout in which the folder is being moved
* @param folderDesc the folder being moved
*/
public static void recordFolderMovedInLayout(IPerson person, UserProfile profile, IUserLayoutFolderDescription folderDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_FOLDER_MOVED_IN_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordFolderMovedInLayoutWorkerTask(person, profile, folderDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a folder is being removed from a user layout
* @param person the person removing the folder
* @param profile the profile of the layout to which the folder is being added
* @param folderDesc the folder being removed from a user layout
*/
public static void recordFolderRemovedFromLayout(IPerson person, UserProfile profile, IUserLayoutFolderDescription folderDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_FOLDER_REMOVED_FROM_LAYOUT)) {
StatsRecorderWorkerTask task = new RecordFolderRemovedFromLayoutWorkerTask(person, profile, folderDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being instantiated
* @param person the person for whom the channel is instantiated
* @param profile the profile of the layout for whom the channel is instantiated
* @param channelDesc the channel being instantiated
*/
public static void recordChannelInstantiated(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_INSTANTIATED)) {
StatsRecorderWorkerTask task = new RecordChannelInstantiatedWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being rendered
* @param person the person for whom the channel is rendered
* @param profile the profile of the layout for whom the channel is rendered
* @param channelDesc the channel being rendered
*/
public static void recordChannelRendered(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_RENDERED)) {
StatsRecorderWorkerTask task = new RecordChannelRenderedWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Record that a channel is being targeted. In other words,
* the user is interacting with the channel via either a
* hyperlink or form submission.
* @param person the person interacting with the channel
* @param profile the profile of the layout in which the channel resides
* @param channelDesc the channel being targeted
*/
public static void recordChannelTargeted(IPerson person, UserProfile profile, IUserLayoutChannelDescription channelDesc) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.RECORD_CHANNEL_TARGETED)) {
StatsRecorderWorkerTask task = new RecordChannelTargetedWorkerTask(person, profile, channelDesc);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
/**
* Save user's statistics ot database
* (when the user logs out or his/her session
* simply times out)
* @param person the person whose statistics have been tracked
*/
public static void saveStatistics(IPerson person) {
if (instance().statsRecorderSettings.get(StatsRecorderSettings.SAVE_STATISTICS)) {
StatsRecorderWorkerTask task = new SaveRDBMStatisticsWorkerTask(person);
task.setStatsRecorder(instance().statsRecorder);
WorkTracker workTracker = instance().threadPool.execute(task);
}
}
}