From b55360719d7c0a59cbfe3a0a7b05559b5e5f3a01 Mon Sep 17 00:00:00 2001 From: Scott Phillips Date: Tue, 15 Apr 2008 04:14:43 +0000 Subject: [PATCH] (Scott Phillips) Added an activity viewer to the Control Panel showing the current user activity on the repository. git-svn-id: http://scm.dspace.org/svn/repo/branches/dspace-1_5_x@2897 9c30dcfa-912a-0410-8fc2-9e0234be79fd --- .../aspect/administrative/ControlPanel.java | 227 ++++++++++++- .../administrative/CurrentActivityAction.java | 320 ++++++++++++++++++ .../app/xmlui/cocoon/BitstreamReader.java | 6 +- .../aspects/Administrative/sitemap.xmap | 2 + .../src/main/webapp/i18n/messages.xml | 16 +- dspace/config/dspace.cfg | 13 +- dspace/docs/configure.html | 7 + 7 files changed, 578 insertions(+), 13 deletions(-) create mode 100644 dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/CurrentActivityAction.java diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/ControlPanel.java b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/ControlPanel.java index 1413fc4e26..add583791a 100644 --- a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/ControlPanel.java +++ b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/ControlPanel.java @@ -44,6 +44,7 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.HashMap; import org.apache.avalon.framework.service.ServiceException; import org.apache.avalon.framework.service.ServiceManager; @@ -69,6 +70,7 @@ import org.dspace.app.xmlui.wing.element.TextArea; import org.dspace.authorize.AuthorizeException; import org.dspace.authorize.AuthorizeManager; import org.dspace.core.ConfigurationManager; +import org.dspace.eperson.EPerson; import org.xml.sax.SAXException; /** @@ -90,6 +92,9 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab private static final Message T_option_dspace = message("xmlui.administrative.ControlPanel.option_dspace"); private static final Message T_option_knots = message("xmlui.administrative.ControlPanel.option_knots"); private static final Message T_option_alerts = message("xmlui.administrative.ControlPanel.option_alerts"); + private static final Message T_seconds = message("xmlui.administrative.ControlPanel.seconds"); + private static final Message T_hours = message("xmlui.administrative.ControlPanel.hours"); + private static final Message T_minutes = message("xmlui.administrative.ControlPanel.minutes"); private static final Message T_JAVA_HEAD = message("xmlui.administrative.ControlPanel.java_head"); private static final Message T_JAVA_VERSION = message("xmlui.administrative.ControlPanel.java_version"); private static final Message T_JAVA_VENDOR = message("xmlui.administrative.ControlPanel.java_vendor"); @@ -121,8 +126,6 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab private static final Message T_knots_column1 = message("xmlui.administrative.ControlPanel.knots_column1"); private static final Message T_knots_column2 = message("xmlui.administrative.ControlPanel.knots_column2"); private static final Message T_knots_column3 = message("xmlui.administrative.ControlPanel.knots_column3"); - private static final Message T_knots_hours = message("xmlui.administrative.ControlPanel.knots_hours"); - private static final Message T_knots_minutes = message("xmlui.administrative.ControlPanel.knots_minutes"); private static final Message T_knots_expired = message("xmlui.administrative.ControlPanel.knots_expired"); private static final Message T_knots_active = message("xmlui.administrative.ControlPanel.knots_active"); private static final Message T_knots_none = message("xmlui.administrative.ControlPanel.knots_none"); @@ -139,6 +142,16 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab private static final Message T_alerts_countdown_keep = message("xmlui.administrative.ControlPanel.alerts_countdown_keep"); private static final Message T_alerts_submit_activate = message("xmlui.administrative.ControlPanel.alerts_submit_activate"); private static final Message T_alerts_submit_deactivate = message("xmlui.administrative.ControlPanel.alerts_submit_deactivate"); + private static final Message T_activity_head = message("xmlui.administrative.ControlPanel.activity_head"); + private static final Message T_activity_sort_time = message("xmlui.administrative.ControlPanel.activity_sort_time"); + private static final Message T_activity_sort_user = message("xmlui.administrative.ControlPanel.activity_sort_user"); + private static final Message T_activity_sort_ip = message("xmlui.administrative.ControlPanel.activity_sort_ip"); + private static final Message T_activity_sort_url = message("xmlui.administrative.ControlPanel.activity_sort_url"); + private static final Message T_activity_sort_agent = message("xmlui.administrative.ControlPanel.activity_sort_Agent"); + private static final Message T_activity_anonymous = message("xmlui.administrative.ControlPanel.activity_anonymous"); + private static final Message T_activity_none = message("xmlui.administrative.ControlPanel.activity_none"); + private static final Message T_activity_hideself = message("xmlui.administrative.ControlPanel.activity_hideself"); + private static final Message T_activity_showself = message("xmlui.administrative.ControlPanel.activity_showself"); private static final Message T_select_panel = message("xmlui.administrative.ControlPanel.select_panel"); /** * The service manager allows us to access the continuation's @@ -149,7 +162,7 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab /** * The four states that this page can be in. */ - private enum OPTIONS {java, dspace,knots,alerts}; + private enum OPTIONS {java, dspace, knots, alerts, activity}; /** * From the servicable api, give us a service manager. @@ -184,6 +197,8 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab option = OPTIONS.knots; if (request.getParameter("alerts") != null) option = OPTIONS.alerts; + if (request.getParameter("activity") != null) + option = OPTIONS.activity; Division div = body.addInteractiveDivision("control-panel", contextPath+"/admin/panel", Division.METHOD_POST, "primary administrative"); div.setHead(T_head); @@ -212,6 +227,16 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab else options.addItemXref("?alerts",T_option_alerts); + String userSortTarget = "?activity"; + if (request.getParameter("sortBy") != null) + userSortTarget += "&sortBy="+request.getParameter("sortBy"); + if (request.getParameter("showSelf") != null) + userSortTarget += "&showSelf="+request.getParameter("showSelf"); + if (option == OPTIONS.activity) + options.addItem().addHighlight("bold").addXref(userSortTarget,"Current Activity"); + else + options.addItemXref(userSortTarget,"Current Activity"); + // The main content: if (option == OPTIONS.java) @@ -222,7 +247,10 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab addWebContinuations(div); else if (option == OPTIONS.alerts) addAlerts(div); - else{ + else if (option == OPTIONS.activity) + addActivity(div); + else + { div.addPara(T_select_panel); } @@ -380,9 +408,9 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab Message lastAccessMessage = null; long lastAccess = System.currentTimeMillis() - knot.getLastAccessTime(); if (lastAccess > 2*60*60*1000) - lastAccessMessage = T_knots_hours.parameterize((lastAccess / (60*60*1000))); + lastAccessMessage = T_hours.parameterize((lastAccess / (60*60*1000))); else - lastAccessMessage = T_knots_minutes.parameterize((lastAccess / (60*1000))); + lastAccessMessage = T_minutes.parameterize((lastAccess / (60*1000))); row = activeFlows.addRow(); row.addCellContent(interpreter); @@ -453,5 +481,192 @@ public class ControlPanel extends AbstractDSpaceTransformer implements Serviceab } + /** The possible sorting parameters */ + private static enum EventSort { TIME, URL, SESSION, AGENT, IP }; + + /** + * Create a list of all activity. + */ + private void addActivity(Division div) throws WingException, SQLException + { + + // 0) Show my requests + Request request = ObjectModelHelper.getRequest(objectModel); + String showSelf = request.getParameter("showSelf"); + if (showSelf == null || !showSelf.equals("false")) + showSelf = "true"; + + // 1) Determine how to sort + EventSort sortBy = EventSort.TIME; + String sortByString = request.getParameter("sortBy"); + if (EventSort.TIME.toString().equals(sortByString)) + sortBy = EventSort.TIME; + if (EventSort.URL.toString().equals(sortByString)) + sortBy = EventSort.URL; + if (EventSort.SESSION.toString().equals(sortByString)) + sortBy = EventSort.SESSION; + if (EventSort.AGENT.toString().equals(sortByString)) + sortBy = EventSort.AGENT; + if (EventSort.IP.toString().equals(sortByString)) + sortBy = EventSort.IP; + + // 2) Sort the events by the requested sorting parameter + java.util.List events = CurrentActivityAction.getEvents(); + Collections.sort(events, new ActivitySort(sortBy)); + Collections.reverse(events); + + // 3) self toggle + if (showSelf.equals("true")) + div.addPara().addXref("?activity&sortBy="+sortBy+"&showSelf=false").addContent(T_activity_hideself); + else + div.addPara().addXref("?activity&sortBy="+sortBy+"&showSelf=true").addContent(T_activity_showself); + + + // 4) Display the results Table + // TABLE: activeUsers + Table activeUsers = div.addTable("users",1,1); + activeUsers.setHead(T_activity_head); + Row row = activeUsers.addRow(Row.ROLE_HEADER); + if (sortBy == EventSort.TIME) + row.addCell().addHighlight("bold").addXref("?activity&sortBy="+EventSort.TIME+"&showSelf="+showSelf).addContent(T_activity_sort_time); + else + row.addCell().addXref("?activity&sortBy="+EventSort.TIME+"&showSelf="+showSelf).addContent(T_activity_sort_time); + + if (sortBy == EventSort.SESSION) + row.addCell().addHighlight("bold").addXref("?activity&sortBy="+EventSort.SESSION+"&showSelf="+showSelf).addContent(T_activity_sort_user); + else + row.addCell().addXref("?activity&sortBy="+EventSort.SESSION+"&showSelf="+showSelf).addContent(T_activity_sort_user); + + if (sortBy == EventSort.IP) + row.addCell().addHighlight("bold").addXref("?activity&sortBy="+EventSort.IP+"&showSelf="+showSelf).addContent(T_activity_sort_ip); + else + row.addCell().addXref("?activity&sortBy="+EventSort.IP+"&showSelf="+showSelf).addContent(T_activity_sort_ip); + + if (sortBy == EventSort.URL) + row.addCell().addHighlight("bold").addXref("?activity&sortBy="+EventSort.URL+"&showSelf="+showSelf).addContent(T_activity_sort_url); + else + row.addCell().addXref("?activity&sortBy="+EventSort.URL+"&showSelf="+showSelf).addContent(T_activity_sort_url); + + if (sortBy == EventSort.AGENT) + row.addCell().addHighlight("bold").addXref("?activity&sortBy="+EventSort.AGENT+"&showSelf="+showSelf).addContent(T_activity_sort_agent); + else + row.addCell().addXref("?activity&sortBy="+EventSort.AGENT+"&showSelf="+showSelf).addContent(T_activity_sort_agent); + + // Keep track of how many individual anonymous users there are, each unique anonymous + // user is assigned an index based upon the servlet session id. + HashMap anonymousHash = new HashMap(); + int anonymousCount = 1; + + int shown = 0; + for (CurrentActivityAction.Event event : events) + { + // Skip out if the user does not want to see their requests. + if (showSelf.equals("false") && event.getEPersonID() == context.getCurrentUser().getID()) + continue; + + shown++; + + Message timeStampMessage = null; + long ago = System.currentTimeMillis() - event.getTimeStamp(); + + if (ago > 2*60*60*1000) + timeStampMessage = T_hours.parameterize((ago / (60*60*1000))); + else if (ago > 60*1000) + timeStampMessage = T_minutes.parameterize((ago / (60*1000))); + else + timeStampMessage = T_seconds.parameterize((ago / (1000))); + + + Row eventRow = activeUsers.addRow(); + + eventRow.addCellContent(timeStampMessage); + int eid = event.getEPersonID(); + EPerson eperson = EPerson.find(context, eid); + if (eperson != null) + { + String name = eperson.getFullName(); + eventRow.addCellContent(name); + } + else + { + // Is this a new anonymous user? + if (!anonymousHash.containsKey(event.getSessionID())) + anonymousHash.put(event.getSessionID(), anonymousCount++); + + eventRow.addCellContent(T_activity_anonymous.parameterize(anonymousHash.get(event.getSessionID()))); + } + eventRow.addCellContent(event.getIP()); + eventRow.addCell().addXref(contextPath+"/"+event.getURL()).addContent("/"+event.getURL()); + eventRow.addCellContent(event.getDectectedBrowser()); + } + + if (shown == 0) + { + activeUsers.addRow().addCell(1, 5).addContent(T_activity_none.parameterize(CurrentActivityAction.MAX_EVENTS)); + } + } + + /** + * Comparator to sort activity events by their access times. + */ + public static class ActivitySort implements Comparator + { + // Sort parameter + private EventSort sortBy; + + public ActivitySort(EventSort sortBy) + { + this.sortBy = sortBy; + } + + /** + * Compare these two activity events based upon the given sort parameter. In the case of a tie, + * allways fallback to sorting based upon the timestamp. + */ + public int compare(E a, E b) + { + // Sort by the given ordering matrix + if (EventSort.URL == sortBy) + { + String aURL = a.getURL(); + String bURL = b.getURL(); + int cmp = aURL.compareTo(bURL); + if (cmp != 0) + return cmp; + } + else if (EventSort.AGENT == sortBy) + { + String aAgent = a.getDectectedBrowser(); + String bAgent = b.getDectectedBrowser(); + int cmp = aAgent.compareTo(bAgent); + if (cmp != 0) + return cmp; + } + else if (EventSort.IP == sortBy) + { + String aIP = a.getIP(); + String bIP = b.getIP(); + int cmp = aIP.compareTo(bIP); + if (cmp != 0) + return cmp; + + } + else if (EventSort.SESSION == sortBy) + { + String aSession = a.getSessionID(); + String bSession = b.getSessionID(); + int cmp = aSession.compareTo(bSession); + if (cmp != 0) + return cmp; + } + + // All ways fall back to sorting by time, when events are equal. + if (a.getTimeStamp() > b.getTimeStamp()) + return 1; // A > B + else if (a.getTimeStamp() > b.getTimeStamp()) + return -1; // B < A + return 0; // A == B + } + } } diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/CurrentActivityAction.java b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/CurrentActivityAction.java new file mode 100644 index 0000000000..b7759e21e2 --- /dev/null +++ b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/aspect/administrative/CurrentActivityAction.java @@ -0,0 +1,320 @@ +/* + * CurrentActivityAction.java + * + * Version: $Revision: 1.1 $ + * + * Date: $Date: 2006/05/01 22:33:39 $ + * + * Copyright (c) 2002, 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 org.dspace.app.xmlui.aspect.administrative; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Queue; + +import org.apache.avalon.framework.parameters.Parameters; +import org.apache.cocoon.acting.AbstractAction; +import org.apache.cocoon.environment.ObjectModelHelper; +import org.apache.cocoon.environment.Redirector; +import org.apache.cocoon.environment.Request; +import org.apache.cocoon.environment.Session; +import org.apache.cocoon.environment.SourceResolver; +import org.dspace.app.xmlui.utils.ContextUtil; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.eperson.EPerson; + +/** + * + * This action simply records pipeline events that it sees, keeping track of the users and + * pages they are viewing. Later the control panel's activity viewer can access this data to + * get a realtime snap shot of current activity of the repository. + * + * @author Scott Phillips + */ + +public class CurrentActivityAction extends AbstractAction +{ + + /** The maximum number of events that are recorded */ + public static int MAX_EVENTS = 250; + + /** The HTTP header that contains the real IP for this request, this is used when DSpace is placed behind a load balancer */ + public static String IP_HEADER = "X-Forwarded-For"; + + /** The ordered list of events, by access time */ + private static Queue events = new LinkedList(); + + /** + * Allow the DSpace.cfg to override our activity max and ip header. + */ + static { + // If the dspace.cfg has a max event count then use it. + if (ConfigurationManager.getProperty("xmlui.controlpanel.activity.max") != null) + MAX_EVENTS = ConfigurationManager.getIntProperty("xmlui.controlpanel.activity.max"); + + if (ConfigurationManager.getProperty("xmlui.controlpanel.activity.ipheader") != null) + IP_HEADER = ConfigurationManager.getProperty("xmlui.controlpanel.activity.ipheader"); + } + + + /** + * Record this current event. + */ + public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, + String source, Parameters parameters) throws Exception + { + Request request = ObjectModelHelper.getRequest(objectModel); + Context context = ContextUtil.obtainContext(objectModel); + + // Create and store our events + Event event = new Event(context,request); + events.add(event); + + // Remove the oldest element from the list if we are over our max + // number of elements. + while(events.size() > MAX_EVENTS) + events.poll(); + + return null; + } + + /** + * @return a list of all current events. + */ + public static List getEvents() + { + List list = new ArrayList(); + list.addAll(events); + return list; + } + + /** + * An object that represents an activity event. + */ + public static class Event + { + /** The Servlet session */ + private String sessionID; + + /** The eperson ID */ + private int epersonID = -1; + + /** The url being viewed */ + private String url; + + /** A timestap of this event */ + private long timestamp; + + /** The user-agent for the request */ + private String userAgent; + + /** The ip address of the requester */ + private String ip; + + /** + * Construct a new activity event, grabing various bits of data about the request from the context and request. + */ + public Event(Context context, Request request) + { + if (context != null) + { + EPerson eperson = context.getCurrentUser(); + if (eperson != null) + epersonID = eperson.getID(); + } + + if (request != null) + { + url = request.getSitemapURI(); + Session session = request.getSession(true); + if (session != null) + sessionID = session.getId(); + + userAgent = request.getHeader("User-Agent"); + + ip = request.getHeader(IP_HEADER); + if (ip == null) + ip = request.getRemoteAddr(); + } + + // The current time + timestamp = System.currentTimeMillis(); + } + + + public String getSessionID() + { + return sessionID; + } + + public int getEPersonID() + { + return epersonID; + } + + public String getURL() + { + return url; + } + + public long getTimeStamp() + { + return timestamp; + } + + public String getUserAgent() + { + return userAgent; + } + + public String getIP() + { + return ip; + } + + /** + * Return the activity viewer's best guess as to what browser or bot was initiating the request. + * + * @return A short name for the browser or bot. + */ + public String getDectectedBrowser() + { + // BOTS + if (userAgent.toLowerCase().contains("google/")) + return "Google (bot)"; + + if (userAgent.toLowerCase().contains("msnbot/")) + return "MSN (bot)"; + + if (userAgent.toLowerCase().contains("googlebot/")) + return "Google (bot)"; + + if (userAgent.toLowerCase().contains("webcrawler/")) + return "WebCrawler (bot)"; + + if (userAgent.toLowerCase().contains("inktomi")) + return "Inktomi (bot)"; + + if (userAgent.toLowerCase().contains("teoma")) + return "Teoma (bot)"; + + // Normal Browsers + if (userAgent.contains("Lotus-Notes/")) + return "Lotus-Notes"; + + if (userAgent.contains("Opera")) + return "Opera"; + + if (userAgent.contains("Safari/")) + return "Safari"; + + if (userAgent.contains("Konqueror/")) + return "Konqueror"; + + // Internet explorer browsers + if (userAgent.contains("MSIE")) + { + if (userAgent.contains("MSIE 8")) + return "MSIE 8"; + if (userAgent.contains("MSIE 7")) + return "MSIE 7"; + if (userAgent.contains("MSIE 6")) + return "MSIE 6"; + if (userAgent.contains("MSIE 5")) + return "MSIE 5"; + + // Can't fine the version number + return "MSIE"; + } + + // Gecko based browsers + if (userAgent.contains("Gecko/")) + { + if (userAgent.contains("Camio/")) + return "Gecko/Camino"; + + if (userAgent.contains("Chimera/")) + return "Gecko/Chimera"; + + if (userAgent.contains("Firebird/")) + return "Gecko/Firebird"; + + if (userAgent.contains("Phoenix/")) + return "Gecko/Phoenix"; + + if (userAgent.contains("Galeon")) + return "Gecko/Galeon"; + + if (userAgent.contains("Firefox/1")) + return "Firefox 1.x"; + + if (userAgent.contains("Firefox/2")) + return "Firefox 2.x"; + + if (userAgent.contains("Firefox/3")) + return "Firefox 3.x"; + + if (userAgent.contains("Firefox/")) + return "Firefox"; // can't find the exact version + + if (userAgent.contains("Netscape/")) + return "Netscape"; + + // Can't find the exact distribution + return "Gecko"; + } + + // Generic browser types (lots of things report these names) + + if (userAgent.contains("KHTML/")) + return "KHTML"; + + if (userAgent.contains("Netscape/")) + return "Netscape"; + + if (userAgent.contains("Mozilla/")) + return "Mozilla"; // Almost everything says they are mozilla. + + // if you get all the way to the end and still nothing, return unknown. + return "Unknown"; + } + } + + + + +} diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/BitstreamReader.java b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/BitstreamReader.java index 014deb9d56..4e777e7f0e 100644 --- a/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/BitstreamReader.java +++ b/dspace-xmlui/dspace-xmlui-api/src/main/java/org/dspace/app/xmlui/cocoon/BitstreamReader.java @@ -46,10 +46,8 @@ import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.sql.SQLException; import java.util.Map; -import java.util.regex.Matcher; import javax.mail.internet.MimeUtility; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.avalon.excalibur.pool.Recyclable; @@ -189,8 +187,8 @@ public class BitstreamReader extends AbstractReader implements Recyclable { this.request = ObjectModelHelper.getRequest(objectModel); this.response = ObjectModelHelper.getResponse(objectModel); - Context context = ContextUtil.obtainContext(objectModel); - + Context context = ContextUtil.obtainContext(objectModel); + // Get our parameters that identify the bitstream int itemID = par.getParameterAsInteger("itemID", -1); int bitstreamID = par.getParameterAsInteger("bitstreamID", -1); diff --git a/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap b/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap index 1ed7408986..ae23dd227f 100644 --- a/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap +++ b/dspace-xmlui/dspace-xmlui-api/src/main/resources/aspects/Administrative/sitemap.xmap @@ -115,6 +115,7 @@ to administer DSpace. + @@ -262,6 +263,7 @@ to administer DSpace. + diff --git a/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml b/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml index 6e32b4ef38..e398561ac6 100644 --- a/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml +++ b/dspace-xmlui/dspace-xmlui-webapp/src/main/webapp/i18n/messages.xml @@ -1446,6 +1446,9 @@ DSpace Configuration Web Continuations System-wide Alerts + {0} h + {0} m + {0} s Java and Operating System Java Runtime Environment Version Java Runtime Environment Vendor @@ -1477,8 +1480,6 @@ Interpreter Last Access State - {0} hours - {0} minutes Expired Active There are no active continuations. @@ -1495,6 +1496,17 @@ Keep the current count down timer Activate Deactivate + Current Activity ({0} pages maximum) + Time Stamp + User + IP Address + URL Page + User-Agent + Anonymous {0} + Hide my page views + Show my page views + Other than yourself, there have been no page views in the past {0} pages. + Use the tabs above to select the information to display diff --git a/dspace/config/dspace.cfg b/dspace/config/dspace.cfg index e1603403e2..cf1c5d8a1b 100644 --- a/dspace/config/dspace.cfg +++ b/dspace/config/dspace.cfg @@ -1165,7 +1165,6 @@ webui.suggest.enable = false # repository home page. #xmlui.user.loginredirect=/profile - # Allow the user to override which theme is used to display a particular page. # When submitting a request add the HTTP parameter "themepath" which corresponds # to a particular theme, that specified theme will be used instead of the any @@ -1212,6 +1211,18 @@ webui.suggest.enable = false # Take this key (just the UA-XXXXXX-X part) and place it here in this parameter. #xmlui.google.analytics.key=UA-XXXXXX-X +# Assign how many page views will be recorded and displayed in the control panel's +# activity viewer. The activity tab allows an administrator to debug problems in a +# running DSpace by understanding who and how their dspace is currently being used. +# The default value is 250. +#xmlui.controlpanel.activity.max = 250 + +# Determine where the control panel's activity viwer recieves an events IP address +# from. If your DSpace is in a load balanced enviornment or otherwise behind a +# context-switch then you will need to set the paramater to the HTTP parameter that +# records the original IP address. +#xmlui.controlpanel.activity.ipheader = X-Forward-For + #---------------------------------------------------------------# #--------------OAI-PMH SPECIFIC CONFIGURATIONS------------------# #---------------------------------------------------------------# diff --git a/dspace/docs/configure.html b/dspace/docs/configure.html index b4c130edaf..e68c87b3ef 100644 --- a/dspace/docs/configure.html +++ b/dspace/docs/configure.html @@ -870,6 +870,13 @@ More information is provide below in Creating a new Media/F If you would like to use google analytics to track general website statistics then provide your google analytics key in this parameter. First sign up for an account at http://analytics.google.com, then create an entry for your repositories website. Analytics will give you a snipit of javascript code to place on your site, inside that snip it is your google analytics key usually found in the line, "_uacct = 'UA-XXXXXXX-X'" Take this key (just the UA-XXXXXX-X part) and place it here in this parameter. + + xmlui.controlpanel.activity.max + + 250 + + Assign how many page views will be recorded and displayed in the control panel's activity viewer. The activity tab allows an administrator to debug problems in a running DSpace by understanding who and how their dspace is currently being used. The default value is 250. + xmlui.force.ssl