Skip to content

Commit

Permalink
STAT-253: Added API method + webservice for processing past site events
Browse files Browse the repository at this point in the history
git-svn-id: https://source.sakaiproject.org/svn/sitestats/trunk@82272 66ffb92e-73f9-0310-93c1-f5514f145a0a
  • Loading branch information
nfgrilo committed Sep 15, 2010
1 parent 59348f9 commit e5d94a4
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,17 @@ public interface StatsUpdateManager {
*/
public boolean collectEvents(Event[] events);

/**
* Collect Sakai events from SAKAI_EVENTS table for a specific site, between specified dates.
* Useful to collect events not processed by SiteStats (occurs when tool is configured to process
* events from sites with the tool placed, and the tool was placed some time after site creation).
* @param siteId The site id
* @param initialDate The initial date of events from SAKAI_EVENT
* @param finalDate The final date of events from SAKAI_EVENT
* @return The number of processed events
*/
public long collectPastSiteEvents(String siteId, Date initialDate, Date finalDate);

/**
* Construct a new Event object using specified arguments. Useful for building Events read from SAKAI_EVENT and SAKAI_SESSION table.
* @param date The SAKAI_EVENT.EVENT_DATE field
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class StatsAggregateJobImpl implements StatefulJob {
private JobRun jobRun = null;
private Object extDbdriver = null;
private String sqlGetEvent = null;
private String sqlPastSiteEvents = null;
private boolean isOracle = false;
private boolean isEventContextSupported = false;

Expand All @@ -81,6 +82,14 @@ public class StatsAggregateJobImpl implements StatefulJob {
"where EVENT_ID >= ? " +
") " +
"WHERE rn BETWEEN ? AND ?";
private String MYSQL_PAST_SITE_EVENTS = "select " + MYSQL_DEFAULT_COLUMNS + MYSQL_CONTEXT_COLUMN + " " +
"from SAKAI_EVENT e join SAKAI_SESSION s on e.SESSION_ID=s.SESSION_ID " +
"where (CONTEXT = ? or (EVENT in ('pres.begin','pres.end') and REF = ?)) " +
"and EVENT_DATE >= ? and EVENT_DATE <= ?";
private String ORACLE_PAST_SITE_EVENTS = "SELECT " + ORACLE_DEFAULT_COLUMNS + ORACLE_CONTEXT_COLUMN + " " +
"from SAKAI_EVENT e join SAKAI_SESSION s on e.SESSION_ID=s.SESSION_ID " +
"where (CONTEXT = ? or (EVENT in ('pres.begin','pres.end') and REF = ?)) " +
"and EVENT_DATE >= ? and EVENT_DATE <= ?";

// Services
private StatsUpdateManager statsUpdateManager = null;
Expand Down Expand Up @@ -397,6 +406,81 @@ private boolean saveJobRun(JobRun jobRun) {
}
return ok;
}

public long collectPastSiteEvents(String siteId, Date initialDate, Date finalDate) {
List<Event> eventsQueue = new ArrayList<Event>();
Connection connection = getEventDbConnection();
PreparedStatement st = null;
ResultSet rs = null;
long count = 0;
long opStart = System.currentTimeMillis();
try{
st = connection.prepareStatement(sqlPastSiteEvents);
st.setString(1, siteId); // CONTEXT = ?
st.setString(2, "/presence/"+siteId+"-presence"); // REF = ?
st.setDate(3, new java.sql.Date(initialDate.getTime())); // EVENT_DATE >= ?
st.setDate(4, new java.sql.Date(finalDate.getTime())); // EVENT_DATE <= ?
rs = st.executeQuery();

while(rs.next()){
Date date = null;
String event = null;
String ref = null;
String context = null;
String sessionUser = null;
String sessionId = null;
try{
//If an exception is launched, iteration is not aborted but no event is added to event queue
date = new Date(rs.getTimestamp("EVENT_DATE").getTime());
event = rs.getString("EVENT");
ref = rs.getString("REF");
sessionUser = rs.getString("SESSION_USER");
sessionId = rs.getString("SESSION_ID");
context = rs.getString("CONTEXT");

eventsQueue.add( statsUpdateManager.buildEvent(date, event, ref, context, sessionUser, sessionId) );
count++;
}catch(Exception e){
if(LOG.isDebugEnabled())
LOG.debug("Ignoring "+event+", "+ref+", "+date+", "+sessionUser+", "+sessionId+" due to: "+e.toString());
}
}

// process events
boolean processedOk = statsUpdateManager.collectEvents(eventsQueue);
eventsQueue.clear();
if(!processedOk){
String returnMessage = "An error occurred while processing/persisting events to db - please check your logs.";
LOG.error(returnMessage);
throw new Exception(returnMessage);
}

}catch(SQLException e){
LOG.error("Unable to collect past site events", e);
}catch(Exception e){
LOG.error("Unable to collect past site due to an unknown cause", e);
}finally{
try{
if(rs != null)
try{
rs.close();
}catch(SQLException e){ }
}finally{
try{
if(st != null)
try{
st.close();
}catch(SQLException e){ }
}finally{
closeEventDbConnection(connection);
}
}
}

long opEnd = System.currentTimeMillis();
LOG.info("Collected "+count+" past events for site "+siteId+" in "+(opEnd-opStart)/1000+" seconds.");
return count;
}


// ################################################################
Expand All @@ -415,12 +499,18 @@ private Connection getEventDbConnection() {
else
sqlGetEvent = ORACLE_GET_EVENT.replaceAll(ORACLE_CONTEXT_COLUMN, "");

// this feature is only available for Sakai >= 2.6.x
sqlPastSiteEvents = ORACLE_PAST_SITE_EVENTS;

}else{
isOracle = false;
if(isEventContextSupported)
sqlGetEvent = MYSQL_GET_EVENT;
else
sqlGetEvent = MYSQL_GET_EVENT.replaceAll(MYSQL_CONTEXT_COLUMN, "");

// this feature is only available for Sakai >= 2.6.x
sqlPastSiteEvents = MYSQL_PAST_SITE_EVENTS;
}
}catch(SQLException e){
LOG.error("Unable to connect Sakai Db", e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Order;
import org.sakaiproject.alias.api.AliasService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.entity.api.EntityManager;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.api.EventTrackingService;
Expand Down Expand Up @@ -288,6 +289,14 @@ public boolean collectEvents(Event[] events) {
return true;
}

/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.StatsUpdateManager#collectPastSiteEvents(java.lang.String, java.util.Date, java.util.Date)
*/
public long collectPastSiteEvents(String siteId, Date initialDate, Date finalDate) {
StatsAggregateJobImpl statsAggregateJob = (StatsAggregateJobImpl) ComponentManager.get("org.sakaiproject.sitestats.api.StatsAggregateJob");
return statsAggregateJob.collectPastSiteEvents(siteId, initialDate, finalDate);
}

/* (non-Javadoc)
* @see org.sakaiproject.sitestats.api.StatsUpdateManager#saveJobRun(org.sakaiproject.sitestats.api.JobRun)
*/
Expand Down
50 changes: 50 additions & 0 deletions sitestats/util/webservices/README.TXT
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Site Stats WebServices
============================================

1. About
2. Installation instructions
3. Call SiteStats webservice
4. Contact



1. About
============================================
Site Stats WebServices offer the ability to invoke some SiteStats API calls through webservices.


2. Installation instructions
============================================
From now on, we will assume that:
- Tomcat folder is located at [TOMCAT_HOME]
- Sakai source folder is located at [SAKAI_SRC]
- SiteStats source folder is located at [SITESTATS_SRC]

2.1 Adding the *.jws files
* cp [SITESTATS_SRC]/util/webservices/*.jws [SAKAI_SRC]/webservices/axis/src/webapp

2.2 Compile & deploy webservices
Webservices compilation and deployment can be made *live* (without stopping Sakai tomcats),
as long as there are no webservices running/processing data (these will be aborted).
* go to [SAKAI_SRC]/webservices
* run: mvn -Dmaven.tomcat.home=[TOMCAT_HOME] clean install sakai:deploy

2.3 Configure Sakai webservices (if not already done)
You can read the following article from Steve Swinsburg about Sakai webservices:
http://steve-on-sakai.blogspot.com/2009/05/enabling-web-services-in-sakai-and.html


3. Call SiteStats webservice
============================================
You can use a custom SOAP client (java code, shell script, ...) to invoke
the SiteStats webservices calls. Alternativelly, you can use 3rd Party tools:
- SOAP Client (Mac): http://ditchnet.org/soapclient/
- SoapUI (Windows): http://www.soapui.org/
- WebServiceStudio (Windows): http://webservicestudio.codeplex.com/


4. Contact
============================================
SiteStats is written by Nuno Fernandes at Universidade Fernando Pessoa.
If you wish, feel free to submit patches or any other contributions.
You may contact us at [email protected].
61 changes: 61 additions & 0 deletions sitestats/util/webservices/SiteStats.jws
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import java.util.Date;

import org.apache.axis.AxisFault;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sakaiproject.authz.api.SecurityService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.sitestats.api.StatsUpdateManager;
import org.sakaiproject.tool.api.Session;
import org.sakaiproject.tool.api.SessionManager;

/**
* SiteStats.jws
*
* Webservice for the SiteStats API.
*
*/
public class SiteStats {
private static final Log LOG = LogFactory.getLog("org.sakaiproject.axis.SiteStats");

private SessionManager sessionManager;
private SecurityService securityService;
private StatsUpdateManager statsUpdateManager;

public SiteStats() {
sessionManager = (SessionManager) ComponentManager.get(SessionManager.class.getName());
securityService = (SecurityService) ComponentManager.get(SecurityService.class.getName());
statsUpdateManager = (StatsUpdateManager) ComponentManager.get(StatsUpdateManager.class.getName());
}

/** Collect site events from SAKAI_EVENT table for a specific site, between specified dates. */
public long collectPastSiteEvents(String sessionid, String siteId, Date initialDate, Date finalDate) throws AxisFault {
Session session = establishSession(sessionid);
if(!securityService.isSuperUser()) {
LOG.warn("NonSuperUser trying to collect past site events: " + session.getUserId());
throw new AxisFault("NonSuperUser trying to collect past site events: " + session.getUserId());
}

return statsUpdateManager.collectPastSiteEvents(siteId, initialDate, finalDate);
}


/**
* Get the Session related to the given sessionid
* @param sessionid the id of the session to retrieve
* @return the session, if it is active
* @throws AxisFault if session is inactive
*/
private Session establishSession(String sessionid) throws AxisFault
{
Session s = sessionManager.getSession(sessionid);
if (s == null) {
throw new AxisFault("Session \""+sessionid+"\" is not active");
}
s.setActive();
sessionManager.setCurrentSession(s);
return s;
}

}

0 comments on commit e5d94a4

Please sign in to comment.