Index: src/org/dspace/app/webui/servlet/BitstreamServlet.java =================================================================== --- src/org/dspace/app/webui/servlet/BitstreamServlet.java (.../DSpace/current) (revision 111) +++ src/org/dspace/app/webui/servlet/BitstreamServlet.java (.../SUEI/trunk) (working copy) @@ -63,9 +63,12 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; +import org.dspace.core.PluginManager; import org.dspace.core.Utils; import org.dspace.handle.HandleManager; +import edu.iupui.ulib.dspace.app.statistics.AbstractUsageEvent; + /** * Servlet for retrieving bitstreams. The bits are simply piped to the user. If * there is an If-Modified-Since header, only a 304 status code @@ -184,6 +187,15 @@ log.info(LogManager.getHeader(context, "view_bitstream", "bitstream_id=" + bitstream.getID())); + AbstractUsageEvent ue = (AbstractUsageEvent)PluginManager.getSinglePlugin(AbstractUsageEvent.class); + ue.setSessionID(request.getSession().getId()); + ue.setSource(request.getRemoteAddr()); + ue.setEperson(context.getCurrentUser()); + ue.setEventType(AbstractUsageEvent.VIEW); // FIXME move to org.dspace.core.Constants? + ue.setObjectType(Constants.BITSTREAM); + ue.setID(bitstream.getID()); + ue.fire(); + // Modification date // TODO: Currently the date of the item, since we don't have dates // for files Index: src/org/dspace/app/webui/servlet/RetrieveServlet.java =================================================================== --- src/org/dspace/app/webui/servlet/RetrieveServlet.java (.../DSpace/current) (revision 111) +++ src/org/dspace/app/webui/servlet/RetrieveServlet.java (.../SUEI/trunk) (working copy) @@ -54,8 +54,11 @@ import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.LogManager; +import org.dspace.core.PluginManager; import org.dspace.core.Utils; +import edu.iupui.ulib.dspace.app.statistics.AbstractUsageEvent; + /** * Servlet for retrieving bitstreams. The bits are simply piped to the user. *

@@ -113,6 +116,15 @@ log.info(LogManager.getHeader(context, "view_bitstream", "bitstream_id=" + bitstream.getID())); + AbstractUsageEvent ue = (AbstractUsageEvent)PluginManager.getSinglePlugin(AbstractUsageEvent.class); + ue.setSessionID(request.getSession().getId()); + ue.setSource(request.getRemoteAddr()); + ue.setEperson(context.getCurrentUser()); + ue.setEventType(AbstractUsageEvent.VIEW); // FIXME move to org.dspace.core.Constants? + ue.setObjectType(Constants.BITSTREAM); + ue.setID(bitstream.getID()); + ue.fire(); + // Set the response MIME type response.setContentType(bitstream.getFormat().getMIMEType()); Index: src/edu/iupui/ulib/dspace/app/statistics/PassiveUsageEvent.java =================================================================== --- src/edu/iupui/ulib/dspace/app/statistics/PassiveUsageEvent.java (.../DSpace/current) (revision 0) +++ src/edu/iupui/ulib/dspace/app/statistics/PassiveUsageEvent.java (.../SUEI/trunk) (revision 160) @@ -0,0 +1,59 @@ +/* + * PassiveUsageEvent.java + * + * Version: $Revision: 0 $ + * + * Date: $Date: 2008/02/08 10:33:00 $ + * + * Copyright (C) 2008, Hewlett-Packard Company and Massachusetts + * Institute of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of the Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT + * HOLDERS OR 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 edu.iupui.ulib.dspace.app.statistics; + +/** + * A null implementation of AbstractUsageEvent to absorb events harmlessly and + * cheaply. + * + * @author Mark H. Wood + * @version $Revision: 0 $ + */ +public class PassiveUsageEvent extends AbstractUsageEvent +{ + /** + * Do nothing and return. Effectively, the event is discarded. + */ + public void fire() + { + return; + } +} Index: src/edu/iupui/ulib/dspace/app/statistics/UsageEventXMLLogger.java =================================================================== --- src/edu/iupui/ulib/dspace/app/statistics/UsageEventXMLLogger.java (.../DSpace/current) (revision 0) +++ src/edu/iupui/ulib/dspace/app/statistics/UsageEventXMLLogger.java (.../SUEI/trunk) (revision 160) @@ -0,0 +1,125 @@ +/* + * UsageEventXmlLogger.java + * + * Version: $Revision: 0 $ + * + * Date: $Date: 2008/02/08 10:33:00 $ + * + * Copyright (C) 2008, Hewlett-Packard Company and Massachusetts + * Institute of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of the Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT + * HOLDERS OR 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 edu.iupui.ulib.dspace.app.statistics; + +import java.io.FileNotFoundException; +import java.io.PrintWriter; +import java.util.Date; + +import org.apache.log4j.Logger; + +import org.dspace.core.ConfigurationManager; + +/** + * Serialize AbstractUsageEvent data to a file as XML. Requires configuration: + * in dspace.cfg specify the path to the file as the value of + * {@code usageEvent.xmlLogger.file}. + * + * @author Mark H. Wood + * @version $Revision: 0 $ + */ +public class UsageEventXMLLogger extends AbstractUsageEvent +{ + /** log4j category */ + private static Logger errorLog = Logger + .getLogger(UsageEventXMLLogger.class); + + /** File on which to write event records */ + private static PrintWriter log = null; + + public UsageEventXMLLogger() + { + super(); + + if (null == log) + { + String logPath = ConfigurationManager + .getProperty("usageEvent.xmlLogger.file"); + if (null == logPath) + { + errorLog + .error("UsageEventXMLLogger unconfigured, will not log events"); + return; + } + + try + { + log = new PrintWriter(logPath); + } + catch (FileNotFoundException e) + { + errorLog + .error( + "UsageEventXMLLogger cannot open file, will not log events", + e); + return; + } + + log.println(""); + log.println(""); + } + } + + /** + * Serialize to a file + */ + public void fire() + { + if (null == log) + return; + + log.print(" "); + + log.print("" + sessionID + ""); + + log.print("" + sourceAddress + ""); + + String epersonName = (null == eperson ? "" : eperson.getEmail()); + log.print("" + epersonName + ""); + + log.println(); + log.flush(); + } +} Index: src/edu/iupui/ulib/dspace/app/statistics/AbstractUsageEvent.java =================================================================== --- src/edu/iupui/ulib/dspace/app/statistics/AbstractUsageEvent.java (.../DSpace/current) (revision 0) +++ src/edu/iupui/ulib/dspace/app/statistics/AbstractUsageEvent.java (.../SUEI/trunk) (revision 160) @@ -0,0 +1,180 @@ +/* + * AbstractUsageEvent.java + * + * Version: $Revision: 0 $ + * + * Date: $Date: 2008/02/08 10:33:00 $ + * + * Copyright (C) 2008, Hewlett-Packard Company and Massachusetts + * Institute of Technology. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of the Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS 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 COPYRIGHT + * HOLDERS OR 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 edu.iupui.ulib.dspace.app.statistics; + +import org.dspace.eperson.EPerson; + +/** + * Base class to be extended by usage event handlers. + * + * @author Mark H. Wood + * @version $Revision: 0 $ + */ +public abstract class AbstractUsageEvent +{ + /** Event is "object has been viewed or downloaded" */ + public static final int VIEW = 1; + + /** Which session sent the query. */ + String sessionID; + + /** Address from which the query was received */ + String sourceAddress; + + /** The EPerson making the request, or null if not logged on */ + EPerson eperson; + + /** What happened? Viewed, logged on, etc. */ + int eventType; + + /** + * Type of object which experienced the event. Bitstream, item, etc. See + * {@link org.dspace.core.Constants Constants} for values. + */ + int objectType; + + /** Identity of specific object which experienced the event */ + int objectID; + + /** + * Because the PluginManager can only call a plugin's niladic constructor, + * the constructor returns an "empty" event. It must be populated using the + * setter methods before "firing". + */ + public AbstractUsageEvent() + { + super(); + } + + /** + * @param id + * opaque session identifier returned by the HTTP request + */ + public void setSessionID(String id) + { + sessionID = id; + } + + /** */ + public String getSessionID() + { + return sessionID; + } + + /** + * @param address + * the address from which the HTTP request came + */ + public void setSource(String address) + { + sourceAddress = address; + } + + /** */ + public String getSource() + { + return sourceAddress; + } + + /** + * @param user + * an object representing the logged-on user, if any. May be + * null. + */ + public void setEperson(EPerson user) + { + eperson = user; + } + + /** */ + public EPerson getEperson() + { + return eperson; + } + + /** + * @param type + * the type of event (view, logon, etc.) + */ + public void setEventType(int type) + { + eventType = type; + } + + /** */ + public int getEventType() + { + return eventType; + } + + /** + * @param type + * the type of object experiencing the event (bitstream, etc.) + */ + public void setObjectType(int type) + { + objectType = type; + } + + /** */ + public int getObjectType() + { + return objectType; + } + + /** + * @param id + * the identifier of the specific object experiencing the event + */ + public void setID(int id) + { + objectID = id; + } + + /** */ + public int getID() + { + return objectID; + } + + /** Called when the event is fully configured, to process the data. */ + abstract public void fire(); +} Index: src/edu/iupui/ulib/dspace/app/statistics/package.html =================================================================== --- src/edu/iupui/ulib/dspace/app/statistics/package.html (.../DSpace/current) (revision 0) +++ src/edu/iupui/ulib/dspace/app/statistics/package.html (.../SUEI/trunk) (revision 158) @@ -0,0 +1,71 @@ + + + +edu.iupui.ulib.dspace.app.statistics package + + + + +

+Defines usage event instrumentation points and provides implementations for +testing. +

+ +

+This package makes usage instrumentation (for statistics, or whatever else +you may fancy) pluggable, while avoiding any unnecessary assumptions about how +usage events may be transmitted, persisted, or processed. +

+ +

+At appropriate points in the processing of user actions, events may be +assembled and "fired". What happens when an event is fired is configurable +via the PluginManager. One must configure a plugin for the AbstractUsageEvent +class, defined in this package, to select an event processing implementation. +

+ +

+Two "stock" implementations are provided. +

+
{@link edu.iupui.ulib.dspace.app.statistics.PassiveUsageEvent PassiveUsageEvent}
+
absorbs events without taking action, resulting in behavior identical + to that of DSpace before this package was added.
+
{@link edu.iupui.ulib.dspace.app.statistics.UsageEventXMLLogger UsageEventXMLLogger}
+
writes event records to a file in an XML format. Suitable mainly for + testing.
+
+

+ + Index: docs/configure.html =================================================================== --- docs/configure.html (.../DSpace/current) (revision 155) +++ docs/configure.html (.../SUEI/trunk) (working copy) @@ -1368,7 +1368,12 @@ of metadata in the appropriate format.

Add the -l option to to pass the ingestion crosswalk a list of elements instead of a whole document, as if the List form of the ingest() method had been called. This is needed to test ingesters for formats like DC that get called with lists of elements instead of a root element.

+

Configuring Usage Instrumentation Plugins

+

A usage instrumentation plugin is configured as a singleton plugin for the abstract class edu.iupui.ulib.dspace.app.statistics.AbstractUsageEvent. +

The XML Logger Plugin

+

The XML Logger plugin is provided as the class edu.iupui.ulib.dspace.app.statistics.UsageEventXMLLogger. It writes event records to a file in a simple XML-like format. If left unconfigured, an error will be noted in the DSpace log and no file will be produced. To specify the file path, provide an absolute path as the value for usageEvent.xmlLogger.file in dspace.cfg.

+
Index: docs/functional.html =================================================================== --- docs/functional.html (.../DSpace/current) (revision 155) +++ docs/functional.html (.../SUEI/trunk) (working copy) @@ -639,6 +639,10 @@

The purpose of the checker is to verify that the content in a DSpace repository has not become corrupted or been tampered with. The functionality can be invoked on an ad-hoc basis from the command line, or configured via cron or similar. Options exist to support large repositories that cannot be entirely checked in one run of the tool. The tool is extensible to new reporting and checking priority approaches.

+

Usage Instrumentation

+ +

DSpace can report usage events, such as bitstream downloads, to a pluggable event processor. This can be used for developing customized usage statistics, for example. A sample event processor plugin writes event records to a file as XML.

+
Index: docs/index.html =================================================================== --- docs/index.html (.../DSpace/current) (revision 155) +++ docs/index.html (.../SUEI/trunk) (working copy) @@ -42,6 +42,7 @@
  • Registration
  • Statistical Reports
  • Checksum Checker
  • +
  • Usage Instrumentation
  • Installation @@ -96,6 +97,7 @@
  • Configuring the checksum checker
  • Configuring Packager Plugins
  • Configuring Crosswalk Plugins
  • +
  • Configuring Usage Instrumentation Plugins