[Ils-source] r1573 - in trunk: src/com/resolutions/forum src/com/resolutions/ils src/com/resolutions/ils/data src/com/resolutions/jobs webapp webapp/api/auth/session/check webapp/api/auth/session/close webapp/api/auth/session/open webapp/api/user/get

scribe at crosswire.org scribe at crosswire.org
Wed May 30 00:53:11 MST 2018


Author: scribe
Date: 2018-05-30 00:53:10 -0700 (Wed, 30 May 2018)
New Revision: 1573

Added:
   trunk/src/com/resolutions/ils/ILSDataObject.java
   trunk/src/com/resolutions/ils/ILSParameters.java
   trunk/src/com/resolutions/ils/ILSRightsAndRoles.java
Modified:
   trunk/src/com/resolutions/forum/ForumMessage.java
   trunk/src/com/resolutions/forum/ForumTopic.java
   trunk/src/com/resolutions/ils/ILSSession.java
   trunk/src/com/resolutions/ils/data/Announcement.java
   trunk/src/com/resolutions/ils/data/Company.java
   trunk/src/com/resolutions/ils/data/Compliance.java
   trunk/src/com/resolutions/ils/data/Course.java
   trunk/src/com/resolutions/ils/data/CourseAttempt.java
   trunk/src/com/resolutions/ils/data/Group.java
   trunk/src/com/resolutions/ils/data/Resource.java
   trunk/src/com/resolutions/ils/data/SecurityMode.java
   trunk/src/com/resolutions/ils/data/Title.java
   trunk/src/com/resolutions/ils/data/UserProfile.java
   trunk/src/com/resolutions/jobs/MgrRecurEMails.java
   trunk/webapp/admin_announceedit.jsp
   trunk/webapp/admin_complianceedit.jsp
   trunk/webapp/admin_coursemanagement.jsp
   trunk/webapp/admin_coursenew.jsp
   trunk/webapp/admin_curricnew.jsp
   trunk/webapp/admin_groupedit.jsp
   trunk/webapp/admin_groupmanagement.jsp
   trunk/webapp/admin_permpresetedit.jsp
   trunk/webapp/admin_profile.jsp
   trunk/webapp/admin_profilemanagement.jsp
   trunk/webapp/admin_resourceedit.jsp
   trunk/webapp/admin_roleedit.jsp
   trunk/webapp/admin_rolemanagement.jsp
   trunk/webapp/admin_sendemail.jsp
   trunk/webapp/admin_studentrecords.jsp
   trunk/webapp/admin_systemmanagement.jsp
   trunk/webapp/api/auth/session/check/index.jsp
   trunk/webapp/api/auth/session/close/index.jsp
   trunk/webapp/api/auth/session/open/index.jsp
   trunk/webapp/api/user/get/index.jsp
   trunk/webapp/employee.jsp
   trunk/webapp/manager_authorization.jsp
Log:
First cut of ils using updated CrossWire tools.  Still work to do.  Saving current state so we don't lose progress


Modified: trunk/src/com/resolutions/forum/ForumMessage.java
===================================================================
--- trunk/src/com/resolutions/forum/ForumMessage.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/forum/ForumMessage.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -7,6 +7,7 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Vector;
+import java.util.List;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import java.util.Date;
@@ -17,7 +18,7 @@
 import org.crosswire.data.DataObject;
 import org.crosswire.utils.HTTPUtils;
 
-public class ForumMessage extends DataObject {
+public class ForumMessage extends DataObject<ForumMessage> {
 	
     private static SimpleDateFormat df  = new SimpleDateFormat("MMMMM dd, yyyy h:mm a");
 
@@ -96,7 +97,7 @@
 		ForumMessage query = new ForumMessage();
 		query.setDateValue("FROM", from);
 		query.setDateValue("TO", to);
-		Vector rows = query.getDataSet(sql);
+		List<ForumMessage> rows = query.getDataSet(sql);
 		return (rows.size() > 0) ? ((ForumMessage) rows.get(0)).getIntValue("CONTRIBUTORCOUNT") : 0;
 	}
     
@@ -114,7 +115,7 @@
         ForumMessage query = new ForumMessage();
         String sql = LOOKUP + " AND FORUMMESSAGEID={FORUMMESSAGEID}";
         query.setForumMessageID(forumMessageID);
-        Vector rows = query.getDataSet(sql);
+        List<ForumMessage> rows = query.getDataSet(sql);
         return (rows.size() > 0) ? (ForumMessage) rows.get(0) : null;
     }
 
@@ -136,7 +137,7 @@
 			query.setBoolValue("FALSE", false);
 		}
 
-		Vector rows = query.getDataSet(sql);
+		List<ForumMessage> rows = query.getDataSet(sql);
 		return (ForumMessage[]) rows.toArray(new ForumMessage[0]);
 	}
 
@@ -264,7 +265,7 @@
 public static void main(String args[]) {
 	DataObject.setDBConnector(new DataObject.DBConnector() {
 		Connection conn = null;
-		public Connection getDBConnection() {
+		public Connection getDBConnection(String noop) {
 			try {
 				String userName = "liferay";
 				String password = "xxxxxxxxxxxx";

Modified: trunk/src/com/resolutions/forum/ForumTopic.java
===================================================================
--- trunk/src/com/resolutions/forum/ForumTopic.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/forum/ForumTopic.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -6,7 +6,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Map;
-import java.util.Vector;
+import java.util.List;
 import java.util.Date;
 import java.awt.Rectangle;
 
@@ -15,7 +15,7 @@
 import org.crosswire.utils.HTTPUtils;
 import java.text.SimpleDateFormat;
 
-public class ForumTopic extends DataObject {
+public class ForumTopic extends DataObject<ForumTopic> {
 
     private static SimpleDateFormat df  = new SimpleDateFormat("MMMMM dd, yyyy h:mm a");
 	
@@ -68,7 +68,7 @@
         ForumTopic query = new ForumTopic();
         String sql = LOOKUP + " AND FORUMTOPICID={FORUMTOPICID}";
         query.setForumTopicID(forumTopicID);
-        Vector rows = query.getDataSet(sql);
+        List<ForumTopic> rows = query.getDataSet(sql);
         return (rows.size() > 0) ? (ForumTopic) rows.get(0) : null;
     }
 
@@ -87,7 +87,7 @@
 			query.setCourseID(courseID);
 		}
 
-		Vector rows = query.getDataSet(sql);
+		List<ForumTopic> rows = query.getDataSet(sql);
 		return (ForumTopic[]) rows.toArray(new ForumTopic[0]);
 	}
 
@@ -175,7 +175,7 @@
 public static void main(String args[]) {
 	DataObject.setDBConnector(new DataObject.DBConnector() {
 		Connection conn = null;
-		public Connection getDBConnection() {
+		public Connection getDBConnection(String noop) {
 			try {
 				String userName = "liferay";
 				String password = "12ray0life12";

Added: trunk/src/com/resolutions/ils/ILSDataObject.java
===================================================================
--- trunk/src/com/resolutions/ils/ILSDataObject.java	                        (rev 0)
+++ trunk/src/com/resolutions/ils/ILSDataObject.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -0,0 +1,24 @@
+package com.resolutions.ils;
+
+import java.util.Map;
+
+import org.crosswire.data.DataObject;
+import org.crosswire.webtools.CustomJsonFields;
+
+public class ILSDataObject<E extends ILSDataObject> extends DataObject<E> /*implements CustomJsonFields */{
+	private static ILSRightsAndRoles rnr;
+/*
+        @Override
+        public Map<String, Object> getJsonMap() {
+                return getData();
+        }
+*/
+
+	public int getCompanyID() {
+		return getIntValue("COMPANYID");
+	}
+	public void setCompanyID(int val) {
+		setIntValue("COMPANYID", val);
+	}
+}
+

Added: trunk/src/com/resolutions/ils/ILSParameters.java
===================================================================
--- trunk/src/com/resolutions/ils/ILSParameters.java	                        (rev 0)
+++ trunk/src/com/resolutions/ils/ILSParameters.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -0,0 +1,11 @@
+package com.resolutions.ils;
+
+import org.crosswire.webtools.Parameters;
+
+public class ILSParameters<E extends ILSParameters<?>> extends Parameters<E> {
+	public ILSSession getILSSession() { return (ILSSession)getUser(); }
+	public void addError(int code, String message) {
+		super.addError(code, message);
+	}
+}
+

Added: trunk/src/com/resolutions/ils/ILSRightsAndRoles.java
===================================================================
--- trunk/src/com/resolutions/ils/ILSRightsAndRoles.java	                        (rev 0)
+++ trunk/src/com/resolutions/ils/ILSRightsAndRoles.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -0,0 +1,83 @@
+package com.resolutions.ils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.crosswire.utils.Sessions;
+import org.crosswire.webtools.RightsAndRoles;
+import org.apache.log4j.Logger;
+
+
+public class ILSRightsAndRoles extends RightsAndRoles {
+	static Logger logger = Logger.getLogger(ILSRightsAndRoles.class);
+
+	static {
+		sysRightsAndRoles = new ILSRightsAndRoles();
+		sessionKeyName = "ilsSession";
+		logger.info("setting sysRightAndRoles to ILSRightAndRoles");
+	}
+
+	@Override
+	public boolean hasRole(RightsAndRoles.User user, String role, RightsAndRoles.UserGroup userGroup) {
+		// assert valid info
+		if (user == null || role == null) return false;
+		// assert we're not asking for group role, as we don't have that concept yet
+		if (userGroup != null) return false;
+
+/* TODO: add this.  Currently we're just going to return false for all roles
+		
+		return Optional.of(user.getJson()).map(r -> r.get("roles"))
+						.map(r -> ((List)r).contains(role))
+						.orElse(false);
+*/
+		return false;
+	}
+
+	@Override
+	public User authenticateUser(String userName, String passwd, String userData) {
+		int split = userName.indexOf(":");
+		// assert we have company
+		if (split == -1) {
+logger.error("no company prefix supplied.  Must supply userName as companyName:userPRNum");
+			return null;
+		}
+		String companyName = userName.substring(0, split);
+		userName = userName.substring(split+1);
+logger.info("authenticating user: " + userName+ "; company: " + companyName);
+		User user = null;
+		try {
+			if (userName != null && passwd != null) {
+				user = ILSSession.login(companyName, userName, passwd);
+				if (user != null && userData != null) user.setValue("userData", userData);
+			}
+		}
+		catch (Exception e) {}
+		return user;
+	}
+
+	@Override
+        public User getCurrentUser(HttpServletRequest request, HttpServletResponse response) {
+                ILSSession user = null;
+                String currentSession = getCurrentSession(request, response);
+                if (currentSession != null) {
+                        Integer userID = (Integer)Sessions.getInstance().getSessionAttribute(currentSession, "userID");
+                        if (userID != null) {
+				String userName = (String)Sessions.getInstance().getSessionAttribute(currentSession, "userName");
+				Integer companyID = (Integer)Sessions.getInstance().getSessionAttribute(currentSession, "companyID");
+				String companyName = (String)Sessions.getInstance().getSessionAttribute(currentSession, "companyName");
+				String defaultFormat = (String)Sessions.getInstance().getSessionAttribute(currentSession, "defaultFormat");
+				user = new ILSSession();
+				user.setUserID(userID);
+				user.setUserName(userName);
+				user.setCompanyID(companyID);
+				user.setCompanyName(companyName);
+logger.info("setting default format to: " + defaultFormat);
+				user.setDefaultFormat(defaultFormat);
+				user.setSessionHash(currentSession);
+                        }
+                }
+                return user;
+        }
+
+
+}
+

Modified: trunk/src/com/resolutions/ils/ILSSession.java
===================================================================
--- trunk/src/com/resolutions/ils/ILSSession.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/ILSSession.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,66 +1,110 @@
 package com.resolutions.ils;
 
-import java.util.Vector;
+import java.util.List;
 
 import org.apache.log4j.Logger;
-import org.crosswire.data.DataObject;
 
+import org.crosswire.webtools.RightsAndRoles;
+import org.crosswire.webtools.RightsAndRoles;
+import org.crosswire.xml.XMLBlock;
+import org.crosswire.utils.Sessions;
+
 import com.resolutions.ils.data.Company;
 import com.resolutions.ils.data.UserProfile;
+import com.resolutions.ils.ILSRightsAndRoles;
 
-public class ILSSession extends DataObject {
-    static String SQL_LOGIN_USER = "SELECT USERPRID, COMPANY.COMPANYID FROM USERPROFILE, COMPANY WHERE COMPANY.COMPANYID=USERPROFILE.COMPANYID AND COMPANY.CONAME={CONAME} AND USERPRNUM={USERPRNUM} AND USERPRPASSWD={USERPRPASSWD} AND USERPRSTATUSID=1";
-    static Logger logger = Logger.getLogger(ILSSession.class);
-    static Logger eventsLogger = Logger.getLogger("EVENTS");
-    private int currentUserID = -1;
+public class ILSSession extends RightsAndRoles.User {
+	static public ILSRightsAndRoles ilsRightsAndRoles = new ILSRightsAndRoles();
+	static String SQL_LOGIN_USER = "SELECT USERPRID, COMPANY.COMPANYID FROM USERPROFILE, COMPANY WHERE COMPANY.COMPANYID=USERPROFILE.COMPANYID AND COMPANY.CONAME={CONAME} AND USERPRNUM={USERPRNUM} AND USERPRPASSWD={USERPRPASSWD} AND USERPRSTATUSID=1";
+	static Logger logger = Logger.getLogger(ILSSession.class);
+	static Logger eventsLogger = Logger.getLogger("EVENTS");
 
-    private ILSSession() {
-    }
+	public static class ILSSessionData extends ILSDataObject<ILSSessionData> {
+	}
 
-    /**
-     * Returns an anonymous session for a company
-     * 
-     * @param companyName
-     * @return
-     */
-    static public ILSSession getAnonymous(int companyID) {
-        ILSSession retVal = new ILSSession();
-        retVal.setIntValue("COMPANYID", companyID);
-        retVal.setIntValue("USERPRID", -1);
-        return retVal;
-    }
+	private ILSSessionData sessionData = new ILSSessionData();
 
-    static public ILSSession login(String companyName, String userID,
-                                   String passwd) {
-        ILSSession retVal = new ILSSession();
-        retVal.setValue("CONAME", companyName);
-        retVal.setValue("USERPRNUM", userID);
-        retVal.setValue("USERPRPASSWD", passwd);
+	public ILSSession() {
+		super();
+		createBlock("ILSSession");
+	}
 
-        Vector rows = retVal.getDataSet(SQL_LOGIN_USER);
-        eventsLogger.info("Login attempted. "+companyName+"."+userID+ ": "+((rows.size()>0)?"success":"failure"));
-        retVal = (rows.size() > 0) ? (ILSSession) rows.get(0) : null;
-        if (retVal != null) {
-            retVal.currentUserID = retVal.getIntValue("USERPRID");
-        }
-        return retVal;
-    }
+	/**
+	* Returns an anonymous session for a company
+	* 
+	* @param companyName
+	* @return
+	*/
+	static public ILSSession getAnonymous(int companyID) {
+		ILSSession retVal = new ILSSession();
+		retVal.sessionData.setIntValue("COMPANYID", companyID);
+		retVal.sessionData.setIntValue("USERPRID", -1);
+		return retVal;
+	}
 
-    public Company getCurrentCompany() {
-        return Company.getCompany(this);
-    }
+	public void setCompanyID(int val) {
+		sessionData.setIntValue("COMPANYID", val);
+		getBlock("ILSSession").setAttribute("companyID", Integer.toString(val));
+	}
+	public void setCompanyName(String val) {
+		sessionData.setValue("CONAME", val);
+		getBlock("ILSSession").setAttribute("companyName", val);
+	}
+	public void setUserName(String val) {
+		super.setUserName(val);
+		sessionData.setValue("USERPRNUM", val);
+	}
+	public int getUserID() {
+		return Integer.parseInt(getInternalUserID());
+	}
+	public void setUserID(int val) {
+		sessionData.setIntValue("USERPRID", val);
+		setInternalUserID(Integer.toString(val));
+	}
+	public void setDefaultFormat(String val) {
+		super.setDefaultFormat(val);
+		Sessions.getInstance().setSessionAttribute(getSessionHash(), "defaultFormat", val);
+	}
 
-    public void setCachedCurrentUserProfile(UserProfile val) {
-	cachedCurrentUserProfile = val;
-    }
+	static public ILSSession login(String companyName, String userName, String passwd) {
+		ILSSession retVal = new ILSSession();
+		retVal.setCompanyName(companyName);
+		retVal.setUserName(userName);
+		retVal.sessionData.setValue("USERPRPASSWD", passwd);
+
+		List<ILSSessionData> rows = retVal.sessionData.getDataSet(SQL_LOGIN_USER);
+		eventsLogger.info("Login attempted. "+companyName+"."+userName+ ": "+((rows.size()>0)?"success":"failure"));
+		if (!rows.isEmpty()) retVal.sessionData = rows.get(0);
+		else retVal = null;
+		if (retVal != null) {
+			String sessionHash = Sessions.getInstance().createSession();
+			int currentUserID = retVal.sessionData.getIntValue("USERPRID");
+			int companyID = retVal.sessionData.getIntValue("COMPANYID");
+			retVal.setCompanyID(companyID);
+			retVal.setUserID(currentUserID);
+			Sessions.getInstance().setSessionAttribute(sessionHash, "companyName", companyName);
+			Sessions.getInstance().setSessionAttribute(sessionHash, "companyID", companyID);
+			Sessions.getInstance().setSessionAttribute(sessionHash, "userName", userName);
+			Sessions.getInstance().setSessionAttribute(sessionHash, "userID", currentUserID);
+			retVal.setSessionHash(sessionHash);
+		}
+		return retVal;
+	}
+
+	public Company getCurrentCompany() {
+		return Company.getCompany(this);
+	}
+
+	public void setCachedCurrentUserProfile(UserProfile val) {
+		cachedCurrentUserProfile = val;
+	}
+
 	private UserProfile cachedCurrentUserProfile = null;
-    public UserProfile getCurrentUserProfile() {
-	if (cachedCurrentUserProfile != null && currentUserID == cachedCurrentUserProfile.getUserProfileID()) return cachedCurrentUserProfile;
-        return (currentUserID == -1) ? new UserProfile() : UserProfile.getUserProfile(this, currentUserID);
-    }
+	public UserProfile getCurrentUserProfile() {
+		if (cachedCurrentUserProfile != null && getUserID() == cachedCurrentUserProfile.getUserProfileID()) return cachedCurrentUserProfile;
+		return (getUserID() == -1) ? new UserProfile() : UserProfile.getUserProfile(this, getUserID());
+	}
 
-    protected DataObject createDataObject() {
-        return new ILSSession();
-    }
+	public int getCompanyID() { return sessionData.getIntValue("COMPANYID"); }
 
 }

Modified: trunk/src/com/resolutions/ils/data/Announcement.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Announcement.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Announcement.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,13 +1,13 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import java.util.Date;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 
-public class Announcement extends DataObject {
+public class Announcement extends ILSDataObject<Announcement> {
 
     static String LOOKUPALL = "SELECT * FROM ANNOUNCEMENT WHERE COMPANYID={COMPANYID} ORDER BY ANNOUNCPOSTDATE DESC";
     static String LOOKUPALLCURRENT = "SELECT * FROM ANNOUNCEMENT WHERE COMPANYID={COMPANYID} AND ANNOUNCEXP>{ANNOUNCEXP} ORDER BY ANNOUNCPOSTDATE DESC";
@@ -18,10 +18,6 @@
     public Announcement() {
     }
 
-    protected DataObject createDataObject() {
-        return new Announcement();
-    }
-
     static public int deleteAnnouncement(ILSSession session, int announcementID) {
         Announcement query = new Announcement();
         query.setAnnounceID(announcementID);
@@ -33,7 +29,7 @@
         Announcement query = new Announcement();
         query.setAnnounceID(announcementID);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUP);
+        List<Announcement> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (Announcement) rows.get(0) : null;
     }
 
@@ -42,18 +38,18 @@
         Announcement query = new Announcement();
         query.setAnnounceTitle(announcementTitle);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUPBYTITLE);
+        List<Announcement> rows = query.getDataSet(LOOKUPBYTITLE);
         return (rows.size() > 0) ? (Announcement) rows.get(0) : null;
     }
 
 
-    static public Vector getAllAnnouncements(ILSSession session) {
+    static public List<Announcement> getAllAnnouncements(ILSSession session) {
         Announcement query = new Announcement();
         query.setCompanyID(session.getCompanyID());
         return query.getDataSet(LOOKUPALL);
     }
 
-    static public Vector getAllCurrentAnnouncements(ILSSession session) {
+    static public List<Announcement> getAllCurrentAnnouncements(ILSSession session) {
         Announcement query = new Announcement();
         query.setCompanyID(session.getCompanyID());
         query.setAnnounceExpiration(new Date());

Modified: trunk/src/com/resolutions/ils/data/Company.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Company.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Company.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,12 +1,17 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
-import java.util.Vector;
+import java.util.List;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import com.resolutions.ils.ILSSession;
+import com.resolutions.ils.ILSRightsAndRoles;
+import com.resolutions.ils.ILSDataObject;
 
-public class Company extends DataObject {
+public class Company extends ILSDataObject<Company> {
+	static {
+		// this is a good entrypoint into our system so we'll be sure our ILSRightsAndRoles is registered
+		new ILSRightsAndRoles();
+	}
 
     static String LOOKUP = "SELECT * FROM COMPANY WHERE COMPANYID={COMPANYID}";
     static String LOOKUPALL = "SELECT * FROM COMPANY";
@@ -15,11 +20,7 @@
     public Company() {
     }
 
-    protected DataObject createDataObject() {
-        return new Company();
-    }
-
-    static public Vector getAllCompanies() {
+    static public List<Company> getAllCompanies() {
         Company query = new Company();
         return query.getDataSet(LOOKUPALL);
     }
@@ -39,21 +40,21 @@
     static public Company getCompany(ILSSession session) {
         Company query = new Company();
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUP);
+        List<Company> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (Company) rows.get(0) : null;
     }
 
     static public Company getCompany(String name) {
         Company query = new Company();
         query.setCompanyName(name);
-        Vector rows = query.getDataSet(LOOKUPBYNAME);
+        List<Company> rows = query.getDataSet(LOOKUPBYNAME);
         return (rows.size() > 0) ? (Company) rows.get(0) : null;
     }
 
     static public Company getCompany(int companyID) {
         Company query = new Company();
         query.setCompanyID(companyID);
-        Vector rows = query.getDataSet(LOOKUP);
+        List<Company> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (Company) rows.get(0) : null;
     }
 

Modified: trunk/src/com/resolutions/ils/data/Compliance.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Compliance.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Compliance.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,20 +1,16 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 
-public class Compliance extends DataObject {
+public class Compliance extends ILSDataObject<Compliance> {
     static String LOOKUP = "SELECT * FROM COMPLIANCE WHERE COMPANYID={COMPANYID}";
     static String DELETE = "DELETE FROM COMPLIANCE WHERE COMPLCID={COMPLCID} AND COMPANYID={COMPANYID}";
     static String LOOKUPCOURSECOMPLIANCIES = "SELECT * FROM COMPLIANCE T1, COURSECOMPLC T2 WHERE T1.COMPLCID=T2.COMPLCID AND T2.COURSID={COURSID} AND T1.COMPANYID={COMPANYID} AND T2.COMPANYID={COMPANYID}";
     static String DELETECOURSECOMPLIANCIES = "DELETE FROM COURSECOMPLC WHERE COURSID={COURSID} AND COMPANYID={COMPANYID}";
     static String ADDCOURSECOMPLIANCE = "INSERT INTO COURSECOMPLC (COMPANYID, COMPLCID, COURSID) VALUES ({COMPANYID}, {COMPLCID}, {COURSID})";
 
-    protected DataObject createDataObject() {
-        return new Compliance();
-    }
-
     static public int deleteCompliance(ILSSession session, int id) {
         Compliance query = new Compliance();
         query.setComplianceID(id);
@@ -27,7 +23,7 @@
         String sql = LOOKUP + " AND COMPLCID={COMPLCID}";
         query.setComplianceID(id);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(sql);
+        List<Compliance> rows = query.getDataSet(sql);
         return (rows.size() > 0) ? (Compliance) rows.get(0) : null;
     }
 
@@ -36,11 +32,11 @@
         String sql = LOOKUP + " AND COMPLCNAME={COMPLCNAME}";
         query.setComplianceName(complianceName);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(sql);
+        List<Compliance> rows = query.getDataSet(sql);
         return (rows.size() > 0) ? (Compliance) rows.get(0) : null;
     }
 
-    static public Vector getCourseCompliancies(ILSSession session, int courseID) {
+    static public List<Compliance> getCourseCompliancies(ILSSession session, int courseID) {
         Compliance query = new Compliance();
         query.setCompanyID(session.getCompanyID());
         query.setValue("COURSID", new Integer(courseID));
@@ -62,7 +58,7 @@
         return query.executeSQL(ADDCOURSECOMPLIANCE);
     }
 
-    static public Vector getAllCompliancies(ILSSession session) {
+    static public List<Compliance> getAllCompliancies(ILSSession session) {
         Compliance query = new Compliance();
         query.setCompanyID(session.getCompanyID());
         return query.getDataSet(LOOKUP);

Modified: trunk/src/com/resolutions/ils/data/Course.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Course.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Course.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -3,9 +3,9 @@
 import org.apache.log4j.Logger;
 import org.crosswire.utils.HTTPUtils;
 import org.crosswire.xml.XMLBlock;
-import org.crosswire.data.*;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Collection;
@@ -13,7 +13,7 @@
 import java.io.File;
 
 
-public class Course extends DataObject {
+public class Course extends ILSDataObject<Course> {
 	static String LOOKUPALLCOURSES          = "SELECT * FROM COURSE WHERE (COURSISCURRICULUM IS NULL OR COURSISCURRICULUM<>'T') AND (COURSISQUICKVIEW IS NULL OR COURSISQUICKVIEW<>'T') AND COMPANYID={COMPANYID} ORDER BY COURSNAME";
 	static String LOOKUPALLCOURSESWACTCHECK = "SELECT * FROM COURSE WHERE (COURSISCURRICULUM IS NULL OR COURSISCURRICULUM<>'T') AND (COURSISQUICKVIEW IS NULL OR COURSISQUICKVIEW<>'T') AND COMPANYID={COMPANYID} AND COURSISACTIVE={COURSISACTIVE} ORDER BY COURSNAME";
 	static String LOOKUPALLQUICKVIEWS       = "SELECT * FROM COURSE WHERE (COURSISCURRICULUM IS NULL OR COURSISCURRICULUM<>'T') AND COURSISQUICKVIEW='T' AND COMPANYID={COMPANYID} ORDER BY COURSNAME";
@@ -66,10 +66,6 @@
 	public Course() {
 	}
 
-	protected DataObject createDataObject() {
-		return new Course();
-	}
-
 	static public int deleteCourse(ILSSession session, int courseID) {
 		Course query = new Course();
 		query.setCourseID(courseID);
@@ -100,17 +96,17 @@
 		String sql = LOOKUP + " AND COURSID={COURSID}";
 		query.setCourseID(courseID);
 		query.setCompanyID(companyID);
-		Vector rows = query.getDataSet(sql);
+		List<Course> rows = query.getDataSet(sql);
 		return (rows.size() > 0) ? (Course) rows.get(0) : null;
 	}
 
 
-	static public Vector getGroupCourses(ILSSession session, int groupID) {
+	static public List<Course> getGroupCourses(ILSSession session, int groupID) {
 		return getGroupCourses(session.getCompanyID(), groupID);
 	}
 
 
-	static public Vector getGroupCourses(int companyID, int groupID) {
+	static public List<Course> getGroupCourses(int companyID, int groupID) {
 		Course query = new Course();
 		query.setCompanyID(companyID);
 		query.setValue("ILSGROUPID", new Integer(groupID));
@@ -123,7 +119,7 @@
 		String sql = LOOKUP + " AND COURSNUM={COURSNUM}";
 		query.setCourseNum(courseNum);
 		query.setCompanyID(session.getCompanyID());
-		Vector rows = query.getDataSet(sql);
+		List<Course> rows = query.getDataSet(sql);
 		return (rows.size() > 0) ? (Course) rows.get(0) : null;
 	}
 
@@ -139,36 +135,36 @@
 		return uniqueCurricula.values();
 	}
 
-	static public Vector getAllCourses(ILSSession session) {
+	static public List<Course> getAllCourses(ILSSession session) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		return query.getDataSet(LOOKUPALLCOURSES);
 	}
 
-	static public Vector getAllCourses(ILSSession session, boolean active) {
+	static public List<Course> getAllCourses(ILSSession session, boolean active) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setCourseActive(active);
 		return query.getDataSet(LOOKUPALLCOURSESWACTCHECK);
 	}
 
-	static public Vector getAllCurricula(ILSSession session) {
+	static public List<Course> getAllCurricula(ILSSession session) {
 		Course query = new Course();
 		query.setValue("COMPANYID", new Integer(session.getCompanyID()));
 		return query.getDataSet(LOOKUPALLCURRICULA);
 	}
 
-	static public Vector getAllQuickViews(ILSSession session) {
+	static public List<Course> getAllQuickViews(ILSSession session) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		return query.getDataSet(LOOKUPALLQUICKVIEWS);
 	}
 
-	static public Vector getActiveUserCourses(ILSSession session, int userID) {
+	static public List<Course> getActiveUserCourses(ILSSession session, int userID) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setValue("USERPRID", new Integer(userID));
-		Vector retVal = query.getDataSet(
+		List<Course> retVal = query.getDataSet(
 			"SELECT * FROM (" +
 			LOOKUPUSERCURRICULUMCOURSESACTIVE +
 			" UNION " +
@@ -180,11 +176,11 @@
 	}
 
 
-	static public Vector getAllUserCourses(ILSSession session, int userID) {
+	static public List<Course> getAllUserCourses(ILSSession session, int userID) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setValue("USERPRID", new Integer(userID));
-		Vector retVal = query.getDataSet(
+		List<Course> retVal = query.getDataSet(
 			"SELECT * FROM (" +
 			LOOKUPUSERCURRICULUMCOURSES +
 			" UNION " + 
@@ -195,12 +191,12 @@
 	}
 
 
-	static public void appendUserCoursesFromAttempts(Vector courses, ILSSession session, int userID) {
+	static public void appendUserCoursesFromAttempts(List<Course> courses, ILSSession session, int userID) {
 		String LOOKUPUSERCOURSEATTEMPTS = "SELECT * FROM COURSE T1, COURSEATTEMPT T2 WHERE T1.COURSID = T2.COURSID AND T2.USERPRID={USERPRID} AND T1.COMPANYID={COMPANYID} AND T2.COMPANYID={COMPANYID}";
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setIntValue("USERPRID", userID);
-		Vector retVal = query.getDataSet(LOOKUPUSERCOURSEATTEMPTS);
+		List<Course> retVal = query.getDataSet(LOOKUPUSERCOURSEATTEMPTS);
 
 		// remove duplicate courses assigned by different paths
 		for (int i = 0; i < retVal.size(); i++) {
@@ -220,23 +216,23 @@
 	}
 
 
-	static public Vector getUserQuickViews(ILSSession session, int userID) {
+	static public List<Course> getUserQuickViews(ILSSession session, int userID) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setValue("USERPRID", new Integer(userID));
 		return query.getDataSet(LOOKUPUSERQUICKVIEWS);
 	}
 
-	static public Vector<Course> getCurriculumCourses(ILSSession session, int curriculumID) {
+	static public List<Course> getCurriculumCourses(ILSSession session, int curriculumID) {
 		Course query = new Course();
 		query.setCompanyID(session.getCompanyID());
 		query.setCourseID(curriculumID);
 		return query.getDataSet(LOOKUPCURRICULUMCOURSES);
 	}
 
-	private Vector<Course> curCourses = null;
+	private List<Course> curCourses = null;
 
-	public Vector<Course> getCurriculumCourses() {
+	public List<Course> getCurriculumCourses() {
 		if (curCourses == null) {
 			Course query = new Course();
 			query.setCompanyID(getCompanyID());

Modified: trunk/src/com/resolutions/ils/data/CourseAttempt.java
===================================================================
--- trunk/src/com/resolutions/ils/data/CourseAttempt.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/CourseAttempt.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -2,15 +2,15 @@
 
 import org.apache.log4j.Logger;
 
-import org.crosswire.data.DataObject;
 import org.crosswire.utils.HTTPUtils;
 import org.crosswire.utils.SMTPMail;
 import org.crosswire.utils.Utils;
 
 import com.resolutions.ils.ILSSession;
+import com.resolutions.ils.ILSDataObject;
 
 import java.util.Properties;
-import java.util.Vector;
+import java.util.List;
 import java.util.Collection;
 import java.util.Arrays;
 import java.util.Set;
@@ -64,10 +64,8 @@
 
 
 
+public class CourseAttempt extends ILSDataObject<CourseAttempt> {
 
-
-public class CourseAttempt extends DataObject {
-
 	public static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); //"EEE MMM dd HH:mm:ss z yyyy");
 	static {
 		df.setTimeZone(TimeZone.getTimeZone("GMT"));
@@ -117,18 +115,14 @@
 	static String LOOKUPCOURSECOMPLETEPENDINGEXPCOURSE = LOOKUPCOURSECOMPLETE + " WHERE CA.COURSATTID IN (" + LOOKUPPENDINGEXPCOURSE + ")";
 
 
-	protected DataObject createDataObject() {
-		return new CourseAttempt();
-	}
-
-	static public Vector getUserCourseAttempts(ILSSession session, int userID, int courseID) {
+	static public List<CourseAttempt> getUserCourseAttempts(ILSSession session, int userID, int courseID) {
 		return getUserCourseAttempts(session, userID, courseID, true);
 	}
 
-	static public Vector getUserCourseAttempts(ILSSession session, int userID, int courseID, boolean includeExpireds) {
+	static public List<CourseAttempt> getUserCourseAttempts(ILSSession session, int userID, int courseID, boolean includeExpireds) {
 		return getUserCourseAttempts(session.getCompanyID(), userID, courseID, includeExpireds);
 	}
-	static public Vector getUserCourseAttempts(int companyID, int userID, int courseID, boolean includeExpireds) {
+	static public List<CourseAttempt> getUserCourseAttempts(int companyID, int userID, int courseID, boolean includeExpireds) {
 		CourseAttempt query = new CourseAttempt();
 		query.setCompanyID(companyID);
 		query.setCourseAttemptUserProfileID(userID);
@@ -169,7 +163,7 @@
 		Properties sysConfig = Utils.getSysConfig(context, companyID);
 		CourseAttempt query = new CourseAttempt();
 		query.setCompanyID(companyID);
-		Vector results = null;
+		List<CourseAttempt> results = null;
 		int count = 0;
 		Course course = null;
 		if (courseID > 0) {
@@ -250,7 +244,7 @@
 		CourseAttempt query = new CourseAttempt();
 		query.setCompanyID(companyID);
 		String WARN = "UPDATE COURSEATTEMPT SET CAWARNEDON"+warningNumber+"=current_timestamp";
-		Vector results = null;
+		List<CourseAttempt> results = null;
 		int count = 0;
 
 		int warnDays = 0;
@@ -323,7 +317,7 @@
 		String sql = LOOKUP + " AND COURSATTID={COURSATTID}";
 		query.setCourseAttemptID(courseAttemptID);
 		query.setCompanyID(session.getCompanyID());
-		Vector rows = query.getDataSet(sql);
+		List<CourseAttempt> rows = query.getDataSet(sql);
 		return (rows.size() > 0) ? (CourseAttempt) rows.get(0) : null;
 	}
 
@@ -369,7 +363,7 @@
 
 	public static CourseAttempt makeCurriculumCourseAttemptIfPassed(ILSSession session, int userProfileID, Course cur, Set<Integer> limitToCASIDs) {
 		boolean isPassed = false;
-		Vector<Course> courses = cur.getCurriculumCourses();
+		List<Course> courses = cur.getCurriculumCourses();
 		if (courses != null) {
 			// if so, then let's check if all courses are passed
 			int  timeframe   = 0;
@@ -382,7 +376,7 @@
 				isPassed = false;
 
 				timeframe += c.getCourseSeatMinutes();
-				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, userProfileID, c.getCourseID(), limitToCASIDs != null);
+				List<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(session, userProfileID, c.getCourseID(), limitToCASIDs != null);
 				if (cas != null) {
 					for (CourseAttempt ca : cas) {
 						if (limitToCASIDs != null && !limitToCASIDs.contains(ca.getCourseAttemptID())) continue;
@@ -437,7 +431,7 @@
 			// find all curricula our user is assigned and check each one
 			for (Course cur : curs) {
 
-				Vector<Course> courses = cur.getCurriculumCourses();
+				List<Course> courses = cur.getCurriculumCourses();
 				if (courses != null) {
 					// is this course a member of the tested curriculum?
 					boolean isPertinent = false;
@@ -480,12 +474,12 @@
 		}
 	}
 
-	static public Vector getSearchUserCourseAttempts(ILSSession session, int locID, int roleID,
+	static public List<CourseAttempt> getSearchUserCourseAttempts(ILSSession session, int locID, int roleID,
 			String lName, String empNum, int statusID, int accessLevel, Date hireStartDate, Date hireEndDate,
 			int managerID, int courseID, int complianceID, Date sDate, Date eDate, boolean reqApprov) {
 		return getSearchUserCourseAttempts(session, locID != -1 ? new HashSet<Integer>(Arrays.asList(new Integer[] { locID })) : null, roleID != -1 ? new HashSet<Integer>(Arrays.asList(new Integer[] { roleID })) : null, lName, empNum, statusID, accessLevel, hireStartDate, hireEndDate, managerID, courseID, complianceID, sDate, eDate, reqApprov);
 	}
-	static public Vector getSearchUserCourseAttempts(ILSSession session, Set<Integer> locIDs, Set<Integer> roleIDs,
+	static public List<CourseAttempt> getSearchUserCourseAttempts(ILSSession session, Set<Integer> locIDs, Set<Integer> roleIDs,
 			String lName, String empNum, int statusID, int accessLevel, Date hireStartDate, Date hireEndDate,
 			int managerID, int courseID, int complianceID, Date sDate, Date eDate, boolean reqApprov) {
 		String sql = "SELECT *, "+
@@ -572,7 +566,7 @@
 		return retVal.getDataSet(sql);
 	}
 
-	static public Vector getCourseAttemptsSummary(ILSSession session, boolean byRole, int managerID, int statusID) {
+	static public List<CourseAttempt> getCourseAttemptsSummary(ILSSession session, boolean byRole, int managerID, int statusID) {
 		String sql = "SELECT IG.GROUPNAME, CAS.CASTATUSDESC, COUNT(CA.CASTATUSID) AS STATUSTOTAL" +
 			"FROM USERGROUP UG, " +
 			"ILSGROUP IG, COURSEATTEMPT CA, COURSEATTSTATUS CAS, USERPROFILE UP " +
@@ -755,7 +749,7 @@
 		boolean error = false;
 
 		ILSSession session = ILSSession.getAnonymous(getCompanyID());
-		session.setIntValue("USERPRID", getCourseAttemptUserProfileID());
+		session.setUserID(getCourseAttemptUserProfileID());
 
 		Properties sysConfig = Utils.getSysConfig(context, getCompanyID());
 		boolean apiEnabled = "on".equals(sysConfig.getProperty("APIEnable", "off"));
@@ -829,7 +823,7 @@
 	logger.debug("certPath: " + cert.getAbsolutePath());
 				if (cert.exists()) {
 	logger.debug("Exists!");
-						byte[] certBytes = DataObject.getBytes(new FileInputStream(cert));
+						byte[] certBytes = ILSDataObject.getBytes(new FileInputStream(cert));
 	logger.debug("certBytes: " + certBytes);
 						return certBytes;
 				}
@@ -865,7 +859,7 @@
 	}
 
 
-	static public Vector getCourseAttempts(ILSSession session, Date sDate, Date eDate, int userProfileID, int courseID) {
+	static public List<CourseAttempt> getCourseAttempts(ILSSession session, Date sDate, Date eDate, int userProfileID, int courseID) {
 		String sql = "SELECT * FROM COURSEATTEMPT CA, USERPROFILE UP, COURSE CR WHERE CA.USERPRID=UP.USERPRID AND CA.COURSID=CR.COURSID AND UP.COMPANYID={COMPANYID}";
 		CourseAttempt retVal = new CourseAttempt();
 		if (sDate != null) {
@@ -893,7 +887,7 @@
 		return retVal.getDataSet(sql);
 	}
 
-	static public Vector getCourseAttempts(ILSSession session, Date sDate, Date eDate) {
+	static public List<CourseAttempt> getCourseAttempts(ILSSession session, Date sDate, Date eDate) {
 		return getCourseAttempts(session, sDate, eDate, -1, -1);
 	}
 
@@ -906,7 +900,7 @@
 		boolean error = false;
 		
 		ILSSession session = ILSSession.getAnonymous(getCompanyID());
-		session.setIntValue("USERPRID", getCourseAttemptUserProfileID());
+		session.setUserID(getCourseAttemptUserProfileID());
 		
 		String passedFailed = null;
 		if (getCourseAttemptStatusID() == CourseAttempt.STATUS_PASSED) {
@@ -952,7 +946,7 @@
 		String CLEAR = "UPDATE COURSEATTEMPT SET CACALLBACKSTATUS=null";
 		CourseAttempt query = new CourseAttempt();
 		query.setCompanyID(companyID);
-		Vector results = null;
+		List<CourseAttempt> results = null;
 		int count = 0;
 
 		String LOOKUPRETRY =	" FROM COURSEATTEMPT CA2 join COURSE CC on CC.COURSID=CA2.COURSID " +
@@ -1033,7 +1027,7 @@
 
 		if (allCurriculumCourses && course.isCourseCurriculum()) {
 			for (Course curCourse : course.getCurriculumCourses()) {
-				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, userProfileID, curCourse.getCourseID(), false);
+				List<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, userProfileID, curCourse.getCourseID(), false);
 				int caid = -1;
 				boolean skipCourse = false;
 				if (cas != null) {
@@ -1089,7 +1083,7 @@
 		}
 		if (allCurriculumCourses && course.isCourseCurriculum()) {
 			for (Course curCourse : course.getCurriculumCourses()) {
-				Vector<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(getCompanyID(), getCourseAttemptUserProfileID(), curCourse.getCourseID(), false);
+				List<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(getCompanyID(), getCourseAttemptUserProfileID(), curCourse.getCourseID(), false);
 				if (cas != null) {
 					for (CourseAttempt ca2 : cas) {
 						if (ca2.getCourseAttemptStatusID() == STATUS_PASSED && !ca2.isCourseAttemptExpired()) {

Modified: trunk/src/com/resolutions/ils/data/Group.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Group.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Group.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,13 +1,13 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import org.crosswire.utils.HTTPUtils;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 import java.util.Date;
 import java.lang.Comparable;
 
-public class Group extends DataObject implements Comparable<Group> {
+public class Group extends ILSDataObject<Group> implements Comparable<Group> {
 
 	public static final int GROUPTYPE_ROLE = 1;
 	public static final int GROUPTYPE_LOCATION = 2;
@@ -39,9 +39,8 @@
 	static String ADDCOURSEGROUP = "INSERT INTO COURSEGROUP (COMPANYID, ILSGROUPID, COURSID) VALUES ({COMPANYID}, {ILSGROUPID}, {COURSID})";
 	static String NEWGROUP = "INSERT INTO ILSGROUP (COMPANYID, GROUPNAME, GROUPDESC) VALUES ({CompanyID}, 'Title', 'Title')";
 
-	protected DataObject createDataObject() {
-		return new Group();
-	}
+	static String GROUP_ACTIVITY = "SELECT G.COMPANYID, G.GROUPTYPEID, G.ILSGROUPID, G.GROUPNAME, SUM(CASE WHEN CRS_COMPLETED>0 THEN 1 ELSE 0 END) as STUDENTS_ACTIVE, COUNT(*) as STUDENTS_TOTAL from ILSGROUP G LEFT JOIN USERGROUP UG ON G.COMPANYID=UG.COMPANYID AND G.ILSGROUPID=UG.ILSGROUPID LEFT JOIN COURSEATTEMPTSTATUS CS on UG.USERPRID=CS.USERPRID WHERE 1=1 ";
+	static String GROUP_ACTIVITY_GROUPBY = " GROUP BY G.COMPANYID, G.GROUPTYPEID, G.ILSGROUPID, G.GROUPNAME";
 
 	static public int deleteGroup(ILSSession session, int id) {
 		Group query = new Group();
@@ -58,7 +57,7 @@
 		Group query = new Group();
 		query.setGroupID(id);
 		query.setCompanyID(new Integer(session.getCompanyID()));
-		Vector rows = query.getDataSet(LOOKUP);
+		List<Group> rows = query.getDataSet(LOOKUP);
 		return (rows.size() > 0) ? (Group) rows.get(0) : null;
 	}
 
@@ -67,7 +66,7 @@
 		query.setGroupTypeID(groupTypeID);
 		query.setGroupName(groupName);
 		query.setCompanyID(new Integer(session.getCompanyID()));
-		Vector rows = query.getDataSet(LOOKUPBYNAME);
+		List<Group> rows = query.getDataSet(LOOKUPBYNAME);
 		return (rows.size() > 0) ? (Group) rows.get(0) : null;
 	}
 
@@ -79,31 +78,45 @@
 		query.setGroupTypeID(groupTypeID);
 		query.setValue("USERDATA", userData);
 		query.setCompanyID(session.getCompanyID());
-		Vector rows = query.getDataSet(LOOKUPBYUSERDATA + (groupTypeID > -1 ? " AND GROUPTYPEID={GROUPTYPEID} " : ""));
+		List<Group> rows = query.getDataSet(LOOKUPBYUSERDATA + (groupTypeID > -1 ? " AND GROUPTYPEID={GROUPTYPEID} " : ""));
 		return (rows.size() > 0) ? (Group) rows.get(0) : null;
 	}
 
-	public Vector<UserProfile> getGroupUsers() {
+	public List<UserProfile> getGroupUsers() {
 		UserProfile query = new UserProfile();
 		query.setValue("COMPANYID", getCompanyID());
 		query.setValue("ILSGROUPID", getGroupID());
-		return (Vector<UserProfile>)query.getDataSet(LOOKUPGROUPUSERS);
+		return query.getDataSet(LOOKUPGROUPUSERS);
 	}
 
-	public Vector<UserProfile> getGroupManagers() {
+	public List<UserProfile> getGroupManagers() {
 		UserProfile query = new UserProfile();
 		query.setValue("COMPANYID", getCompanyID());
 		query.setValue("ILSGROUPID", getGroupID());
-		return (Vector<UserProfile>)query.getDataSet(LOOKUPGROUPMANAGERS);
+		return query.getDataSet(LOOKUPGROUPMANAGERS);
 	}
-	public Vector<Course> getGroupCourses() {
+	public List<Course> getGroupCourses() {
 		return Course.getGroupCourses(getCompanyID(), getGroupID());
 	}
 
-	static public Vector getUserGroups(ILSSession session, int groupTypeID, int userID) {
+	public static List<Group> getGroupsActivity() {
+		return getGroupsActivity(-1);
+	}
+	public static List<Group> getGroupsActivity(int groupTypeID) {
+		String sql = GROUP_ACTIVITY;
+		Group query = new Group();
+		if (groupTypeID != -1) {
+			sql += " AND GROUPTYPEID={GROUPTYPEID} ";
+			query.setGroupTypeID(groupTypeID);
+		}
+		sql += GROUP_ACTIVITY_GROUPBY;
+		return query.getDataSet(sql);
+	}
+
+	static public List<Group> getUserGroups(ILSSession session, int groupTypeID, int userID) {
 	return getUserGroups(session.getCompanyID(), groupTypeID, userID);
 	}
-	static public Vector getUserGroups(int companyID, int groupTypeID, int userID) {
+	static public List<Group> getUserGroups(int companyID, int groupTypeID, int userID) {
 		Group query = new Group();
 		query.setCompanyID(new Integer(companyID));
 		query.setValue("USERPRID", new Integer(userID));
@@ -134,7 +147,7 @@
 		return query.executeSQL(ADDUSERGROUP);
 	}
 
-	static public Vector getManagerGroups(ILSSession session, int groupTypeID, int userID) {
+	static public List<Group> getManagerGroups(ILSSession session, int groupTypeID, int userID) {
 		Group query = new Group();
 		query.setCompanyID(new Integer(session.getCompanyID()));
 		query.setValue("USERPRID", new Integer(userID));
@@ -189,14 +202,14 @@
 		return query.executeSQL(ADDCOURSEGROUP);
 	}
 
-	static public Vector getCourseGroups(ILSSession session, int courseID) {
+	static public List<Group> getCourseGroups(ILSSession session, int courseID) {
 		Group query = new Group();
 		query.setCompanyID(new Integer(session.getCompanyID()));
 		query.setValue("COURSID", new Integer(courseID));
 		return query.getDataSet(LOOKUPCOURSEGROUPS);
 	}
 
-	static public Vector getAllGroups(ILSSession session, int groupTypeID) {
+	static public List<Group> getAllGroups(ILSSession session, int groupTypeID) {
 		Group query = new Group();
 		query.setCompanyID(new Integer(session.getCompanyID()));
 		query.setGroupTypeID(groupTypeID);
@@ -282,6 +295,15 @@
 		xml.append(" groupID=\""+ getGroupID()+"\"");
 		xml.append(" groupTypeID=\""+ getGroupTypeID()+"\"");
 		xml.append(" groupName=\""+HTTPUtils.canonize(getGroupName())+"\"");
+
+		// these are possible from activity report
+		if (getValue("STUDENTS_TOTAL") != null) {
+			xml.append(" studentsTotal=\""+getIntValue("STUDENTS_TOTAL")+"\"");
+		}
+		if (getValue("STUDENTS_ACTIVE") != null) {
+			xml.append(" studentsActive=\""+getIntValue("STUDENTS_ACTIVE")+"\"");
+		}
+
 		xml.append(" userData=\""+getStringValue("USERDATA")+"\"");
 		if (detail == DETAIL_HEADERONLY) {
 			xml.append("/>");
@@ -290,7 +312,7 @@
 			xml.append(">\n");
 			xml.append(" <groupDescription>"+HTTPUtils.canonize(getGroupDescription())+"</groupDescription>\n");
 			if (detail == DETAIL_EXTRA) {
-				Vector<UserProfile> users = getGroupManagers();
+				List<UserProfile> users = getGroupManagers();
 				xml.append("<managerProfiles count=\""+users.size()+"\">");
 				for (UserProfile u: users) {
 					xml.append(u.toXML(DETAIL_HEADERONLY));
@@ -302,7 +324,7 @@
 					xml.append(u.toXML(DETAIL_HEADERONLY));
 				}
 				xml.append("</userProfiles>");
-				Vector<Course> courses = getGroupCourses();
+				List<Course> courses = getGroupCourses();
 				xml.append("<courses count=\""+courses.size()+"\">");
 				for (Course c: courses) {
 					xml.append(c.toXML(DETAIL_HEADERONLY));

Modified: trunk/src/com/resolutions/ils/data/Resource.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Resource.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Resource.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,13 +1,13 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import java.util.Date;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 import java.util.Calendar;
 import java.util.GregorianCalendar;
 
-public class Resource extends DataObject {
+public class Resource extends ILSDataObject<Resource> {
 
     static String LOOKUPALL = "SELECT * FROM RESOURCE WHERE COMPANYID={COMPANYID} ORDER BY RESOURCPOSTDATE DESC";
     static String LOOKUPALLCURRENT = "SELECT * FROM RESOURCE WHERE COMPANYID={COMPANYID} AND RESOURCEXP>{RESOURCEXP} ORDER BY RESOURCPOSTDATE DESC";
@@ -18,13 +18,11 @@
     public Resource() {
     }
 
-    protected DataObject createDataObject() { return new Resource(); }
-
     static public Resource getResource(ILSSession session, int resourceID) {
         Resource query = new Resource();
         query.setResourceID(resourceID);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUP);
+        List<Resource> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (Resource)rows.get(0) : null;
     }
 
@@ -32,17 +30,17 @@
         Resource query = new Resource();
         query.setResourceTitle(resourceTitle);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUPBYTITLE);
+        List<Resource> rows = query.getDataSet(LOOKUPBYTITLE);
         return (rows.size() > 0) ? (Resource)rows.get(0) : null;
     }
 
-    static public Vector getAllResources(ILSSession session) {
+    static public List<Resource> getAllResources(ILSSession session) {
     Resource query = new Resource();
         query.setCompanyID(session.getCompanyID());
         return query.getDataSet(LOOKUPALL);
     }
 
-    static public Vector getAllCurrentResources(ILSSession session) {
+    static public List<Resource> getAllCurrentResources(ILSSession session) {
     Resource query = new Resource();
         query.setCompanyID(session.getCompanyID());
         query.setResourceExpiration(new Date());

Modified: trunk/src/com/resolutions/ils/data/SecurityMode.java
===================================================================
--- trunk/src/com/resolutions/ils/data/SecurityMode.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/SecurityMode.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,10 +1,10 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 
-public class SecurityMode extends DataObject {
+public class SecurityMode extends ILSDataObject<SecurityMode> {
 
     static String LOOKUPALLSECURITYMODES =
             "SELECT * FROM SECURITYMODE WHERE COMPANYID={COMPANYID}";
@@ -13,9 +13,6 @@
     static String DELETE =
             "DELETE FROM SECURITYMODE WHERE SECMODDESC={SECMODDESC} AND COMPANYID={COMPANYID}";
 
-    protected DataObject createDataObject() {
-        return new SecurityMode();
-    }
 
     public void defaultAll() {
     }
@@ -31,11 +28,11 @@
         SecurityMode query = new SecurityMode();
         query.setSecurityModeDescription(secModDesc);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUP);
+        List<SecurityMode> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (SecurityMode) rows.get(0) : null;
     }
 
-    static public Vector getAllSecurityModes(ILSSession session) {
+    static public List<SecurityMode> getAllSecurityModes(ILSSession session) {
         SecurityMode query = new SecurityMode();
         query.setCompanyID(session.getCompanyID());
         return query.getDataSet(LOOKUPALLSECURITYMODES);

Modified: trunk/src/com/resolutions/ils/data/Title.java
===================================================================
--- trunk/src/com/resolutions/ils/data/Title.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/Title.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,11 +1,11 @@
 package com.resolutions.ils.data;
 
-import org.crosswire.data.*;
 import com.resolutions.ils.ILSSession;
-import java.util.Vector;
+import com.resolutions.ils.ILSDataObject;
+import java.util.List;
 import java.util.Date;
 
-public class Title extends DataObject {
+public class Title extends ILSDataObject<Title> {
 
     static String LOOKUPALLEMPTITLES =
             "SELECT * FROM EMPTITLE WHERE COMPANYID={COMPANYID}";
@@ -16,9 +16,6 @@
     static String DELETE =
             "DELETE FROM EMPTITLE WHERE EMPTITLEID={EMPTITLEID} AND COMPANYID={COMPANYID}";
 
-    protected DataObject createDataObject() {
-        return new Title();
-    }
 
     public void defaultAll() {
     }
@@ -34,7 +31,7 @@
         Title query = new Title();
         query.setTitleID(id);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUP);
+        List<Title> rows = query.getDataSet(LOOKUP);
         return (rows.size() > 0) ? (Title) rows.get(0) : null;
     }
 
@@ -42,11 +39,11 @@
         Title query = new Title();
         query.setTitleName(titleName);
         query.setCompanyID(session.getCompanyID());
-        Vector rows = query.getDataSet(LOOKUPBYNAME);
+        List<Title> rows = query.getDataSet(LOOKUPBYNAME);
         return (rows.size() > 0) ? (Title) rows.get(0) : null;
     }
 
-    static public Vector getAllTitles(ILSSession session) {
+    static public List<Title> getAllTitles(ILSSession session) {
         Title query = new Title();
         query.setCompanyID(session.getCompanyID());
         return query.getDataSet(LOOKUPALLEMPTITLES);

Modified: trunk/src/com/resolutions/ils/data/UserProfile.java
===================================================================
--- trunk/src/com/resolutions/ils/data/UserProfile.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/ils/data/UserProfile.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 import java.util.Calendar;
 import java.util.Date;
 import java.util.Properties;
-import java.util.Vector;
+import java.util.List;
 import java.util.Set;
 import java.util.HashSet;
 import java.util.Arrays;
@@ -22,11 +22,12 @@
 import javax.servlet.ServletContext;
 
 import org.apache.log4j.Logger;
-import org.crosswire.data.DataObject;
 import org.crosswire.utils.SMTPMail;
 import org.crosswire.utils.HTTPUtils;
+import org.crosswire.webtools.CustomXMLDoc;
 
 import com.resolutions.ils.ILSSession;
+import com.resolutions.ils.ILSDataObject;
 import com.resolutions.ils.Utils;
 import java.util.HashMap;
 import java.io.StringWriter;
@@ -34,7 +35,7 @@
 import org.owasp.html.PolicyFactory; 
 
 
-public class UserProfile extends DataObject {
+public class UserProfile extends ILSDataObject<UserProfile> implements CustomXMLDoc {
 	
 	public static final int STATUS_ACTIVE = 1;
 	public static final int STATUS_INACTIVE = 0;
@@ -100,7 +101,9 @@
 		+ "";
 static String RECURRENT_TRAINING_REPORT_LIMIT_TO_MANAGER = " AND CASS.USERPRID IN (SELECT DISTINCT UG.USERPRID FROM MANAGERGROUP MG LEFT JOIN USERGROUP UG ON UG.COMPANYID = MG.COMPANYID AND UG.ILSGROUPID=MG.ILSGROUPID WHERE MG.COMPANYID={COMPANYID} AND MG.USERPRID={USERPRID}) AND (GROUPTYPEID <> 2 OR ILSGROUPID IN (SELECT ILSGROUPID FROM MANAGERGROUP WHERE COMPANYID={COMPANYID} AND USERPRID={USERPRID}))";
 
+	static String STUDENT_GROUP_ACTIVITY = "SELECT G.COMPANYID, G.ILSGROUPID, G.GROUPNAME, G.GROUPTYPEID, UP.*, CS.* from ILSGROUP G LEFT JOIN USERGROUP UG ON G.COMPANYID=UG.COMPANYID AND G.ILSGROUPID=UG.ILSGROUPID LEFT JOIN COURSEATTEMPTSTATUS CS on UG.COMPANYID=CS.COMPANYID AND UG.USERPRID=CS.USERPRID LEFT JOIN USERPROFILE UP ON UP.COMPANYID=CS.COMPANYID AND UP.USERPRID=CS.USERPRID WHERE G.ILSGROUPID={ILSGROUPID}";
 
+
     private boolean isRoleLoaded              = false;
     private boolean isWorkgroupLoaded         = false;
     private boolean isCourseSummaryDataLoaded = false;
@@ -111,12 +114,9 @@
     static Logger logger = Logger.getLogger(Course.class);
     static Logger eventsLogger = Logger.getLogger("EVENTS");
 
-    public UserProfile() {
-    }
+	public UserProfile() {
+	}
 
-    protected DataObject createDataObject() {
-        return new UserProfile();
-    }
 
 	static PolicyFactory sanitizer = new HtmlPolicyBuilder()
 		.allowElements("a")
@@ -132,7 +132,9 @@
 	// perform sanitation
 	public void setValue(String key, Object val) {
 		if (val instanceof String) {
-			val = sanitize((String)val);
+			String s = sanitize((String)val);
+			s = s.replaceAll("&#64;", "@");
+			val = s;
 		}
 		super.setValue(key, val);
 	}
@@ -179,7 +181,7 @@
         filter.setCompanyID(session.getCompanyID());
         filter.setUserProfileStatusID(UserProfile.STATUS_INACTIVE);
         filter.setUserProfileInactiveDate(olderThan);
-        Vector<UserProfile> rows = filter.getDataSet(COUNTWOULDBEDELETES);
+        List<UserProfile> rows = filter.getDataSet(COUNTWOULDBEDELETES);
         if (rows.size() > 0) {
         	return rows.get(0).getIntValue("WOULDBE");
         }
@@ -193,7 +195,7 @@
         int origC = orig.getCompanyID();
         int thisC = getCompanyID();
         String[] keyCols = new String[] {"COMPANYID", "USERPRID"};
-        Vector<String> modCols = getModifiedFields(orig);
+        List<String> modCols = getModifiedFields(orig);
         int retVal = save(orig, "USERPROFILE", keyCols);
         if (retVal > 0) {
         	if (modCols.contains("USERPRNUM")) {
@@ -290,7 +292,7 @@
         String sql = LOOKUP + " AND USERPRID={USERPRID}";
         retVal.setUserProfileID(userProfileID);
         retVal.setCompanyID(companyID);
-        Vector<UserProfile> rows = retVal.getDataSet(sql);
+        List<UserProfile> rows = retVal.getDataSet(sql);
         return (rows.size() > 0) ? rows.get(0) : null;
     }
 
@@ -299,7 +301,7 @@
         String sql = LOOKUP + " AND USERPRNUM={USERPRNUM}";
         retVal.setUserProfileNum(userProfileNum);
         retVal.setCompanyID(session.getCompanyID());
-        Vector<UserProfile> rows = retVal.getDataSet(sql);
+        List<UserProfile> rows = retVal.getDataSet(sql);
         return (rows.size() > 0) ? rows.get(0) : null;
     }
 
@@ -308,7 +310,7 @@
         String sql = LOOKUP + " AND USERPROFILE.USERDATA={USERDATA}";
         retVal.setValue("USERDATA", userData);
         retVal.setCompanyID(session.getCompanyID());
-        Vector<UserProfile> rows = retVal.getDataSet(sql);
+        List<UserProfile> rows = retVal.getDataSet(sql);
         return (rows.size() > 0) ? rows.get(0) : null;
     }
 
@@ -348,12 +350,12 @@
 	" LEFT JOIN USERCOURSEASSIGNMENTS A ON A.COMPANYID=U.COMPANYID AND A.USERPRID=U.USERPRID" +
 	" LEFT OUTER JOIN COURSEATTEMPTSTATUS CA ON CA.COMPANYID = A.COMPANYID AND CA.USERPRID = A.USERPRID AND A.COURSID = CA.COURSID AND CA.CAEXPIREDON IS NULL";
 
-	static public Vector<UserProfile> getSearchUserProfiles(ILSSession session, int locID, int roleID,
+	static public List<UserProfile> getSearchUserProfiles(ILSSession session, int locID, int roleID,
                                                String lName, String empNum, int statusID, int accessLevel, Date hireStartDate, Date hireEndDate, int managerID, boolean preloadCourseData) {
 		return getSearchUserProfiles(session, locID != -1 ? new HashSet<Integer>(Arrays.asList(new Integer[] { locID })) : null, roleID != -1 ? new HashSet<Integer>(Arrays.asList(new Integer[] { roleID })) : null, lName, empNum, statusID, accessLevel, hireStartDate, hireEndDate, managerID, preloadCourseData);
 	}
 
-    static public Vector<UserProfile> getSearchUserProfiles(ILSSession session, Set<Integer> locIDs, Set<Integer> roleIDs,
+    static public List<UserProfile> getSearchUserProfiles(ILSSession session, Set<Integer> locIDs, Set<Integer> roleIDs,
                                                String lName, String empNum, int statusID, int accessLevel, Date hireStartDate, Date hireEndDate, int managerID, boolean preloadCourseData) {
 
     	long timer = System.currentTimeMillis();
@@ -431,7 +433,7 @@
                         " (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=UP2.USERPRID AND GROUPTYPEID=2) WORKGROUP," + 
                         " (SELECT MAX(GROUPNAME) FROM USERGROUP UG JOIN ILSGROUP IG ON UG.ILSGROUPID=IG.ILSGROUPID AND UG.USERPRID=UP2.USERPRID AND GROUPTYPEID=1) ROLE " +
                         " FROM " + tables + " WHERE " + where;
-		Vector<UserProfile> results = retVal.getDataSet(sql);
+		List<UserProfile> results = retVal.getDataSet(sql);
         
     	logger.debug("getSearchUserProfiles after getDataSet["+results.size()+"] ("+(System.currentTimeMillis() - timer)+")"); timer = System.currentTimeMillis();
     	
@@ -445,13 +447,13 @@
         return results;
     }
 
-	static public Vector<UserProfile> getManagers(ILSSession session) {
+	static public List<UserProfile> getManagers(ILSSession session) {
 		return getManagers(session, false);
 	}
-	static public Vector<UserProfile> getManagers(ILSSession session, boolean excludeRecurEmailOverrides) {
+	static public List<UserProfile> getManagers(ILSSession session, boolean excludeRecurEmailOverrides) {
 		return getManagers(session.getCompanyID(), excludeRecurEmailOverrides);
 	}
-	static public Vector<UserProfile> getManagers(int companyID, boolean excludeRecurEmailOverrides) {
+	static public List<UserProfile> getManagers(int companyID, boolean excludeRecurEmailOverrides) {
 
 		UserProfile retVal = new UserProfile();
 
@@ -462,7 +464,7 @@
 			sql += " AND UP.USERPMGRRECUREMAILSOVERRIDE<>'T'";
 		}
 
-		Vector<UserProfile> results = retVal.getDataSet(sql);
+		List<UserProfile> results = retVal.getDataSet(sql);
 
 		return results;
 	}
@@ -508,7 +510,7 @@
 	
 
     // default is byLocation
-    static public Vector<UserProfile> getSumUserProfiles(ILSSession session, int locID, int roleID,
+    static public List<UserProfile> getSumUserProfiles(ILSSession session, int locID, int roleID,
                                                String lName, String empNum, int statusID, int accessLevel, Date hireStartDate, Date hireEndDate, int managerID, boolean byRole) {
         UserProfile retVal = new UserProfile();
         String sql    = USERGROUPCOURSESUMMARY;
@@ -563,17 +565,17 @@
         return retVal.getDataSet(sql + " OPTION (RECOMPILE)");
     }
 
-	public Vector<UserProfile> getManagerRecurrentTrainingReport(int daysTilExpire) {
+	public List<UserProfile> getManagerRecurrentTrainingReport(int daysTilExpire) {
 		int limitToManager = (getUserProfileAccessLevel() <= UserProfile.ACCESS_MANAGER) ? getUserProfileID() : -1;
 		return UserProfile.getManagerRecurrentTrainingReport(this.getCompanyID(), daysTilExpire, limitToManager);
 	}
-	static public Vector<UserProfile> getManagerRecurrentTrainingReport(ILSSession session, int daysTilExpire) {
+	static public List<UserProfile> getManagerRecurrentTrainingReport(ILSSession session, int daysTilExpire) {
 		return getManagerRecurrentTrainingReport(session, daysTilExpire, -1);
 	}
-	static public Vector<UserProfile> getManagerRecurrentTrainingReport(ILSSession session, int daysTilExpire, int limitToManager) {
+	static public List<UserProfile> getManagerRecurrentTrainingReport(ILSSession session, int daysTilExpire, int limitToManager) {
 		return getManagerRecurrentTrainingReport(session.getCompanyID(), daysTilExpire, limitToManager);
 	}
-	static public Vector<UserProfile> getManagerRecurrentTrainingReport(int companyID, int daysTilExpire, int limitToManagerID) {
+	static public List<UserProfile> getManagerRecurrentTrainingReport(int companyID, int daysTilExpire, int limitToManagerID) {
 		UserProfile retVal = new UserProfile();
 		String sql = RECURRENT_TRAINING_REPORT;
 		retVal.setCompanyID(companyID);
@@ -582,7 +584,7 @@
 			sql += RECURRENT_TRAINING_REPORT_LIMIT_TO_MANAGER;
 			retVal.setUserProfileID(limitToManagerID);
 		}
-		Vector<UserProfile> results = retVal.getDataSet(sql + " OPTION (RECOMPILE)");
+		List<UserProfile> results = retVal.getDataSet(sql + " OPTION (RECOMPILE)");
 		for (UserProfile up: results) {
 			up.isRoleLoaded = true;
 			up.isWorkgroupLoaded = true;
@@ -592,7 +594,7 @@
 
     public UserProfile []getManagers() {
         String sql = LOOKUP + " AND USERPRID IN (" + LOOKUPMANAGERS + ") AND USERPRSTATUSID=" + STATUS_ACTIVE;
-        Vector<UserProfile> rows = this.getDataSet(sql);
+        List<UserProfile> rows = this.getDataSet(sql);
         return rows.toArray(new UserProfile[0]);
     }
 
@@ -680,6 +682,13 @@
         return getDateValue("USERPRHIREDATE");
     }
 
+	public boolean isEmployedFor(int days) {
+		Calendar cal = Calendar.getInstance();
+		cal.setTime(getUserProfileHireDate());
+		cal.add(Calendar.DAY_OF_YEAR, days);
+		return cal.getTime().getTime() < new Date().getTime();
+	}
+
     public Date getUserProfileTermDate() {
         return getDateValue("USERPRTERMDATE");
     }
@@ -725,6 +734,7 @@
     }
 
     public void setUserProfileMiddleName(String val) {
+logger.info("UserProfile.setUserProfileMiddleName: "+val);
         setValue("USERPRMNAME", val);
     }
 
@@ -784,6 +794,14 @@
         return ("T".equals(getValue("USERPMGRRECUREMAILSOVERRIDE")));
     }
 
+    public void setMgrComplEmailOverride(boolean val) {
+        setValue("USERPMGRCOMPLEMAILSOVERRIDE", (val) ? "T" : "F");
+    }
+
+    public boolean isMgrComplEmailOverride() {
+        return ("T".equals(getValue("USERPMGRCOMPLEMAILSOVERRIDE")));
+    }
+
     public void setSecondaryValidationOverride(boolean val) {
         setValue("USERPRSECONDLOGINOVERRIDE", (val) ? "T" : "F");
     }
@@ -843,7 +861,7 @@
 		return getRoles();
 	}
 	public String getRoles() {
-		Vector tmpg = Group.getUserGroups(getCompanyID(), Group.GROUPTYPE_ROLE, getUserProfileID());
+		List<Group> tmpg = Group.getUserGroups(getCompanyID(), Group.GROUPTYPE_ROLE, getUserProfileID());
 		String upRole = "";
 		if (tmpg != null) {
 			for (Object g : tmpg) {
@@ -866,7 +884,7 @@
 		return getWorkgroups();
 	}
 	public String getWorkgroups() {
-		Vector tmpg = Group.getUserGroups(getCompanyID(), Group.GROUPTYPE_LOCATION, getUserProfileID());
+		List<Group> tmpg = Group.getUserGroups(getCompanyID(), Group.GROUPTYPE_LOCATION, getUserProfileID());
 		String upLocation = "";
 		if (tmpg != null) {
 			for (Object g : tmpg) {
@@ -877,16 +895,16 @@
 		return upLocation;
 	}
 
-	public Vector getUserGroups() {
+	public List<Group> getUserGroups() {
 		return getUserGroups(-1);
 	}
-	public Vector<Group> getUserGroups(int groupTypeID) {
+	public List<Group> getUserGroups(int groupTypeID) {
 		Group query = new Group();
 		query.setIntValue("COMPANYID", getCompanyID());
 		query.setGroupTypeID(groupTypeID);
 		query.setValue("USERPRID", getUserProfileID());
 		
-		return (Vector<Group>)query.getDataSet(LOOKUPUSERGROUPS+(groupTypeID != -1 ? "GROUPTYPEID={GROUPTYPEID}" : ""));
+		return query.getDataSet(LOOKUPUSERGROUPS+(groupTypeID != -1 ? "GROUPTYPEID={GROUPTYPEID}" : ""));
 	}
 
     public int getCoursesOpen(ILSSession ilsSession) {
@@ -926,15 +944,14 @@
     }
 */
     private void loadCourseSummaryData(ILSSession ilsSession) {
-        Vector courses = Course.getAllUserCourses(ilsSession, getUserProfileID());
+        List<Course> courses = Course.getAllUserCourses(ilsSession, getUserProfileID());
         Date lastDate = null;
         int completed = 0;
         int failed = 0;
         int open = 0;
         for (int k = 0; k < courses.size(); k++) {
             Course cc = (Course) courses.get(k);
-            Vector cas = CourseAttempt.getUserCourseAttempts(ilsSession,
-                    getUserProfileID(), cc.getCourseID());
+            List<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, getUserProfileID(), cc.getCourseID());
             CourseAttempt ca = null;
             for (int i = 0; i < cas.size(); i++) {
             	ca = (CourseAttempt) cas.get(i);
@@ -975,7 +992,7 @@
         UserProfile filter = new UserProfile();
         filter.setCompanyID(company.getCompanyID());
         filter.setUserProfileEMail(email);
-        Vector<UserProfile> results = filter.getDataSet(LOOKUPBYEMAIL);
+        List<UserProfile> results = filter.getDataSet(LOOKUPBYEMAIL);
         for (Object o: results) {
         	UserProfile p = (UserProfile)o;
 		if (p.getUserProfileStatusID() == STATUS_ACTIVE) {
@@ -998,6 +1015,84 @@
         return results.size();
     }
 
+	public static synchronized void runMgrComplReport(ServletContext servletContext, int groupActivityThresholdPercent, int onlyManagersOlderThanDays) {
+		for (Group g : Group.getGroupsActivity()) {
+			long groupActivePercent = Math.round((double)g.getIntValue("STUDENTS_ACTIVE") / (double)g.getIntValue("STUDENTS_TOTAL") * 100);
+			long groupInactivePercent = 100 - groupActivePercent;
+			if (groupInactivePercent >= groupActivityThresholdPercent) {
+				for (UserProfile m : g.getGroupManagers()) {
+					if (m.isEmployedFor(onlyManagersOlderThanDays) && !m.isMgrComplEmailOverride()) {
+						m.emailMgrComplReport(servletContext, g.getGroupID());
+					}
+				}
+			}
+		}
+	}
+
+	public static synchronized StringWriter getGroupComplReport(int companyID, int groupID) {
+		StringWriter out = new StringWriter();
+		SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
+		UserProfile query = new UserProfile();
+
+		query.setIntValue("ILSGROUPID", groupID);
+		List<UserProfile> userProfiles = query.getDataSet(STUDENT_GROUP_ACTIVITY);
+
+		out.write("Last Name,");
+		out.write("First Name,");
+		out.write("Emp ID,");
+//TODO: translate these
+		out.write("Policyholder,");
+		out.write("Role,");
+		out.write("Completed Courses,Open Courses,Last Course Completed\n");
+		for (UserProfile up : userProfiles) {
+			Date lastDate = up.getDateValue("CACOMPLETEDATE");
+			String eDate = (lastDate != null) ? df.format(lastDate) : "";
+			out.write("\""+up.getUserProfileLastName().replaceAll("\"", "\"\"") + "\",");
+			out.write("\""+up.getUserProfileFirstName().replaceAll("\"", "\"\"") + "\",");
+			out.write("\""+up.getUserProfileNum().replaceAll("\"", "\"\"") + "\",");
+			out.write("\""+up.getWorkgroups().replaceAll("\"", "\"\"") + "\",");
+			out.write("\""+up.getRoles().replaceAll("\"", "\"\"") + "\",");
+			out.write(up.getStringValue("CRS_COMPLETED") + ",");
+			out.write(up.getStringValue("CRS_FAILED") + ",");
+			out.write(eDate);
+			out.write("\n");
+		}
+		return out;
+	}
+
+
+	public synchronized void emailMgrComplReport(ServletContext context, int groupID) {
+		SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
+		StringWriter out = new StringWriter();
+		String companyName = Company.getCompany(getCompanyID()).getCompanyName();
+		out.write(companyName + "\n");
+		out.write(getUserProfileFirstName() + " " + getUserProfileLastName() + "\n");
+		out.write("Report Run " + df.format(new Date()) + "\n\n");
+		out.write("Compliance Report\n\n");
+		out.write(getGroupComplReport(getCompanyID(), groupID).toString());
+		Properties sysConfig = Utils.getSysConfig(context, getCompanyID());
+		String subjectTemplate = sysConfig.getProperty("EmailTemplate8Subject");
+		String bodyTemplate    = sysConfig.getProperty("EmailTemplate8Body");
+		String from            = sysConfig.getProperty("SendMailFrom");
+		try {
+			String to = getUserProfileEMail();
+			java.util.HashMap params = new java.util.HashMap();
+			params.put("CONAME", companyName);
+			params.put("SITEURL", sysConfig.getProperty("SiteURL", "your training site"));
+			params.putAll(this.getData());
+			String subject = Utils.replaceParams(subjectTemplate, params);
+			String body    = Utils.replaceParams(bodyTemplate, params);
+			body += sysConfig.getProperty("SendMailSig", "");
+logger.info("sending email to: " + to + "; body: " + body);
+			SMTPMail.sendEmail(sysConfig, from, to, subject, body, "recurrentReport.csv", out.toString(), "text/csv", true);
+		}
+		catch (Exception e) {
+			e.printStackTrace();
+		}
+		Utils.closeMailConnection();
+	}
+
+
 	public synchronized void emailMgrRecurReport(ServletContext context, int daysTilDue) {
 		StringWriter out = new StringWriter();
 		SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
@@ -1005,7 +1100,7 @@
 		String subjectTemplate = sysConfig.getProperty("EmailTemplate7Subject");
 		String bodyTemplate    = sysConfig.getProperty("EmailTemplate7Body");
 		String from            = sysConfig.getProperty("SendMailFrom");
-		Vector<UserProfile> userProfiles = getManagerRecurrentTrainingReport(daysTilDue);
+		List<UserProfile> userProfiles = getManagerRecurrentTrainingReport(daysTilDue);
 		int expiredCount = 0;
 		for (UserProfile up : userProfiles) {
 			if (up.getValue("DAYSEXPIRED") != null) ++expiredCount;
@@ -1126,7 +1221,7 @@
 
 
 			if (detail == DETAIL_EXTRA) {
-				Vector<Group> groups = getUserGroups();
+				List<Group> groups = getUserGroups();
 				xml.append("<groups count=\""+groups.size()+"\">");
 				for (Group g : groups) {
 					xml.append(g.toXML(DETAIL_HEADERONLY));

Modified: trunk/src/com/resolutions/jobs/MgrRecurEMails.java
===================================================================
--- trunk/src/com/resolutions/jobs/MgrRecurEMails.java	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/src/com/resolutions/jobs/MgrRecurEMails.java	2018-05-30 07:53:10 UTC (rev 1573)
@@ -19,6 +19,7 @@
 
 import com.resolutions.ils.Utils;
 import com.resolutions.ils.data.Company;
+import com.resolutions.ils.data.Group;
 import com.resolutions.ils.data.UserProfile;
 
 public class MgrRecurEMails implements Job {
@@ -87,6 +88,64 @@
 			}
 		}
 		logger.info("Finished Batch Job MgrRecurEmail");
+		logger.info("Running Batch Job MgrComplianceEmail");
+		for (Object o : Company.getAllCompanies()) {
+			Company c = (Company)o;
+			Properties sysConfig = Utils.getSysConfig(servletContext, c.getCompanyID());
+			boolean enableComplEmails = "on".equals(sysConfig.getProperty("EmailEnableManagerComplReport", ""));
+			int complReportManagersOlderThanNumDays = 30; try { complReportManagersOlderThanNumDays = Integer.parseInt(sysConfig.getProperty("ComplReportNumDays")); } catch (Exception e) {}
+			int complReportDayOfMonth = 1; try { complReportDayOfMonth = Integer.parseInt(sysConfig.getProperty("ComplReportDayOfMonth")); } catch (Exception e) {}
+			int complReportDay = Calendar.SUNDAY; try { complReportDay = Integer.parseInt(sysConfig.getProperty("ComplReportDay")); } catch (Exception e) {}
+			int complReportThresholdPercent = 100; try { complReportThresholdPercent = Integer.parseInt(sysConfig.getProperty("ComplReportThresholdPercent")); } catch (Exception e) {}
+			String complReportFreq = sysConfig.getProperty("ComplReportFreq");
+			if (enableComplEmails) {
+                                Properties lastJobs = new Properties();
+                                File propName = new File(servletContext.getRealPath("/WEB-INF/lastjobs."+c.getCompanyID() + ".properties"));
+                                if (propName.exists()) {
+					try {
+						FileInputStream propFile = new FileInputStream(propName);
+						lastJobs.load(propFile);
+						propFile.close();
+					}
+					catch (Exception e) {}
+                                }
+				Calendar cal = GregorianCalendar.getInstance();
+				cal.set(2000, 1, 1);
+				Date lastDate = cal.getTime(); try { lastDate = df.parse(lastJobs.getProperty("ManagerComplReportEmails")); } catch (Exception e) {}
+				cal.setTime(lastDate);
+
+				if ("MONTHLY".equals(complReportFreq)) {
+					// Add 1 month and a day to last report run, then back up until we hit our target date
+					cal.add(Calendar.MONTH, 1);
+					if (cal.get(Calendar.DAY_OF_MONTH) < complReportDayOfMonth) cal.add(Calendar.MONTH, -1);
+					cal.set(Calendar.DAY_OF_MONTH, complReportDayOfMonth);
+				}
+				else if ("WEEKLY".equals(complReportFreq)) {
+					cal.add(Calendar.DAY_OF_MONTH, 7);
+					if (cal.get(Calendar.DAY_OF_WEEK) < complReportDay) cal.add(Calendar.DAY_OF_MONTH, -1*cal.get(Calendar.DAY_OF_WEEK));
+					int adjust = cal.get(Calendar.DAY_OF_WEEK)-complReportDay;
+					if (adjust > 0) cal.add(Calendar.DAY_OF_MONTH, adjust*-1);
+				}
+				else {
+					cal.add(Calendar.DAY_OF_MONTH, 1);
+				}
+				cal.add(Calendar.HOUR, -4);	// be sure we don't miss out date by just a few hours. report shouldn't take more than this long to run the reports.
+				lastDate = cal.getTime();
+				if (new Date().after(lastDate)) {
+
+					UserProfile.runMgrComplReport(servletContext, complReportThresholdPercent, complReportManagersOlderThanNumDays);
+
+					lastJobs.setProperty("ManagerComplReportEmails", df.format(new Date()));
+					try {
+						FileOutputStream propFile = new FileOutputStream(propName);
+						lastJobs.store(propFile, "last saved from MgrComplEmail batch job");
+						propFile.close();
+					}
+					catch (Exception e) {}
+				}
+			}
+		}
+		logger.info("Finished Batch Job MgrComplianceEmail");
 	}
 
 }

Modified: trunk/webapp/admin_announceedit.jsp
===================================================================
--- trunk/webapp/admin_announceedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_announceedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,6 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.util.List" %>
 <%@ page import="java.util.Iterator" %>

Modified: trunk/webapp/admin_complianceedit.jsp
===================================================================
--- trunk/webapp/admin_complianceedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_complianceedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
 <%@ page import="java.net.URL" %>
@@ -160,7 +160,7 @@
   </table>
 
 <%
-    Vector compls = Compliance.getAllCompliancies(ilsSession);
+    List<Compliance> compls = Compliance.getAllCompliancies(ilsSession);
 %>
 
 <form name="certdel" method="post" action="admin_complianceedit.jsp">
@@ -186,7 +186,7 @@
                             </tr>
 <%
      for (int i = 0; i < compls.size(); i++) {
-          Compliance c = (Compliance)compls.get(i);
+          Compliance c = compls.get(i);
 %>
                             <tr <%= (current.getComplianceID() == c.getComplianceID())?"class=\"selectedRow\"":""%>>
                               <td><input id="roleck<%=i%>" type="checkbox" name="complid" value="<%=c.getComplianceID()%>"></td>

Modified: trunk/webapp/admin_coursemanagement.jsp
===================================================================
--- trunk/webapp/admin_coursemanagement.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_coursemanagement.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
@@ -68,15 +68,15 @@
     }
 
 
-    Vector courses       = Course.getAllCourses(ilsSession);
-    Vector quickviews    = Course.getAllQuickViews(ilsSession);
-    Vector curricula     = Course.getAllCurricula(ilsSession);
+    List<Course> courses       = Course.getAllCourses(ilsSession);
+    List<Course> quickviews    = Course.getAllQuickViews(ilsSession);
+    List<Course> curricula     = Course.getAllCurricula(ilsSession);
 
     final String sort = request.getParameter("sort");
 
     if (sort != null) {
         for (int i = 0; i < 3; i++) {
-            Vector c = (i == 0) ? courses : (i == 1) ? quickviews : curricula;
+            List<Course> c = (i == 0) ? courses : (i == 1) ? quickviews : curricula;
             if (c != null) {
                 java.util.Collections.sort(c, new Comparator() {
                     public int compare(Object o1, Object o2) {
@@ -146,7 +146,7 @@
         <a href="admin_coursenew.jsp"></a>
         <%
   for (int i = 0; i < 2; i++) {
-     Vector cs = null;
+     List<Course> cs = null;
      if (i < 1) {
          cs = courses;
      }
@@ -201,7 +201,7 @@
                   </tr>
                   <%
     for (int j = 0; j < cs.size(); j++) {
-        Course cc = (Course)cs.get(j);
+        Course cc = cs.get(j);
         String timeFrame  = cc.getCourseSeatTimeText();
         Date tDate = cc.getCoursePostDate();
         String postDate = (tDate != null) ? df.format(tDate) : "";
@@ -268,7 +268,7 @@
                             </tr>
 <%
     for (int j = 0; j < curricula.size(); j++) {
-        Course cc = (Course)curricula.get(j);
+        Course cc = curricula.get(j);
         String timeFrame  = cc.getCourseSeatTimeText();
         Date tDate = cc.getCoursePostDate();
         String postDate = (tDate != null) ? df.format(tDate) : "";

Modified: trunk/webapp/admin_coursenew.jsp
===================================================================
--- trunk/webapp/admin_coursenew.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_coursenew.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,11 +4,12 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
 <%@ page import="java.util.Comparator" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
 <%@ page import="java.util.List" %>
+<%@ page import="java.util.ArrayList" %>
 <%@ page import="java.net.URL" %>
 <%@ page import="java.text.SimpleDateFormat" %>
 <%@ page import="org.apache.commons.fileupload.*" %>
@@ -84,8 +85,8 @@
         try { if (val != null) current.setCourseQuickView(Integer.parseInt(val)>0); } catch (Exception e) { logger.error(e); }
     }
 
-    Vector tmp = Compliance.getCourseCompliancies(ilsSession, current.getCourseID());
-    int currentComplianceID = ((tmp != null) && (tmp.size()>0)) ? ((Compliance)tmp.get(0)).getComplianceID() : -1;
+    List<Compliance> tmp = Compliance.getCourseCompliancies(ilsSession, current.getCourseID());
+    int currentComplianceID = (tmp != null && !tmp.isEmpty()) ? tmp.get(0).getComplianceID() : -1;
 
     if ("revokeExpCourses".equals(action)) {
     	if (current.getCourseID() > 0) {
@@ -227,7 +228,7 @@
         statusMsg = "Your changes have been saved.";
     }
 
-    Vector certs = Compliance.getAllCompliancies(ilsSession);
+    List<Compliance> certs = Compliance.getAllCompliancies(ilsSession);
 
 %>
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
@@ -374,8 +375,7 @@
                               <td width="130"><select name="cert">
                                   <option <%=(currentComplianceID == -1) ? "selected=\"selected\"":""%> value="-1">Select Certification</option>
                                   <%
-     for (int i = 0; i < certs.size(); i++) {
-          Compliance cert = (Compliance)certs.get(i);
+     for (Compliance cert : certs) {
 %>
                                   <option value="<%=cert.getComplianceID()%>" <%=(cert.getComplianceID() == currentComplianceID)?"selected=\"true\"":""%>><%=cert.getComplianceName()%></option>
                                   <%
@@ -519,7 +519,7 @@
     <br/>
 <%
 if (current.getCourseID() > 0) {
-    Vector roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
 
     final String sort = request.getParameter("sort");
 
@@ -538,11 +538,7 @@
                 });
         }
     }
-    Vector tmp2 = Group.getCourseGroups(ilsSession, current.getCourseID());
-    Vector inCourse = new Vector();
-    for (int i = 0; i < tmp2.size(); i++) {
-      inCourse.add(new Integer(((Group)tmp2.get(i)).getGroupID()));
-    }
+    List<Integer> inCourse = Group.getCourseGroups(ilsSession, current.getCourseID()).stream().map(Group::getGroupID).collect(Collectors.toList());
 %>
 <form name="courserolesave" method="post" action="admin_coursenew.jsp">
     <input type="hidden" name="action" value="SaveRoles"/>

Modified: trunk/webapp/admin_curricnew.jsp
===================================================================
--- trunk/webapp/admin_curricnew.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_curricnew.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,8 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
@@ -307,8 +308,8 @@
         <br>
 <%
 if (current.getCourseID() > 0) {
-    Vector courses = Course.getAllCourses(ilsSession);
-    Vector tmp = Course.getCurriculumCourses(ilsSession, current.getCourseID());
+    List<Course> courses = Course.getAllCourses(ilsSession);
+    List<Course> tmp = Course.getCurriculumCourses(ilsSession, current.getCourseID());
     final HashMap inCourse = new HashMap();
     for (int i = 0; i < tmp.size(); i++) {
       inCourse.put(new Integer(((Course)tmp.get(i)).getCourseID()), new Integer(((Course)tmp.get(i)).getIntValue("SORTORDER")));
@@ -396,7 +397,7 @@
 %>
 <%
 if (current.getCourseID() > 0) {
-    Vector roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
 
     if (sort != null) {
         if (roles != null) {
@@ -414,11 +415,7 @@
         }
     }
 
-    Vector tmp2 = Group.getCourseGroups(ilsSession, current.getCourseID());
-    Vector inCourse = new Vector();
-    for (int i = 0; i < tmp2.size(); i++) {
-      inCourse.add(new Integer(((Group)tmp2.get(i)).getGroupID()));
-    }
+    List<Integer> inCourse = Group.getCourseGroups(ilsSession, current.getCourseID()).stream().map(Group::getGroupID).collect(Collectors.toList());
 %>
 <form name="courserolesave" method="post" action="admin_curricnew.jsp">
     <input type="hidden" name="action" value="SaveRoles"/>

Modified: trunk/webapp/admin_groupedit.jsp
===================================================================
--- trunk/webapp/admin_groupedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_groupedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,8 +4,9 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
 <%@ page import="java.net.URL" %>
@@ -133,7 +134,7 @@
 <p><br>
                         <%
 if (current.getGroupID() > 0) {
-    Vector courses = Course.getAllCourses(ilsSession);
+    List<Course> courses = Course.getAllCourses(ilsSession);
 
     final String sort = request.getParameter("sort");
 
@@ -156,11 +157,7 @@
         }
     }
     courses.addAll(Course.getAllCurricula(ilsSession));
-    Vector tmp = Course.getGroupCourses(ilsSession, current.getGroupID());
-    Vector inGroup = new Vector();
-    for (int i = 0; i < tmp.size(); i++) {
-        inGroup.add(new Integer(((Course)tmp.get(i)).getCourseID()));
-    }
+    List<Integer> inGroup = Course.getGroupCourses(ilsSession, current.getGroupID()).stream().map(Course::getCourseID).collect(Collectors.toList());
 %>
                                             </p>
     <form name="groupcoursesave" method="post" action="admin_groupedit.jsp">

Modified: trunk/webapp/admin_groupmanagement.jsp
===================================================================
--- trunk/webapp/admin_groupmanagement.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_groupmanagement.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
@@ -47,7 +47,7 @@
         }
     }
 
-    Vector<Group> groups        = (Vector<Group>) Group.getAllGroups(ilsSession, Group.GROUPTYPE_LOCATION);
+    List<Group> groups = Group.getAllGroups(ilsSession, Group.GROUPTYPE_LOCATION);
 
     final String sort = request.getParameter("sort");
 

Modified: trunk/webapp/admin_permpresetedit.jsp
===================================================================
--- trunk/webapp/admin_permpresetedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_permpresetedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
 <%@ page import="java.net.URL" %>
@@ -237,7 +237,7 @@
   </table>
 
 <%
-    Vector compls = SecurityMode.getAllSecurityModes(ilsSession);
+    List<SecurityMode> compls = SecurityMode.getAllSecurityModes(ilsSession);
 %>
 
 <form name="certdel" method="post" action="admin_permpresetedit.jsp">

Modified: trunk/webapp/admin_profile.jsp
===================================================================
--- trunk/webapp/admin_profile.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_profile.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -6,14 +6,14 @@
 <%@ page import="org.crosswire.utils.GeoData" %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.Set" %>
+<%@ page import="java.util.Arrays" %>
+<%@ page import="java.util.ArrayList" %>
 <%@ page import="java.util.HashSet" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.util.PriorityQueue" %>
-<%@ page import="java.io.File" %>
-<%@ page import="java.net.URL" %>
-<%@ page import="java.util.Properties" %>
 <%@ page import="java.text.SimpleDateFormat" %>
 <%@ page import="org.apache.log4j.Logger" %>
 
@@ -66,23 +66,17 @@
         catch (Exception e) { logger.error(e, e); }
     }
 
-	Vector<Integer> currentRoles = null;
-	Vector tmp = Group.getUserGroups(ilsSession, Group.GROUPTYPE_ROLE, current.getUserProfileID());
-	if (tmp != null && tmp.size() > 0) {
-		currentRoles = new Vector<Integer>();
-		for (Object o : tmp) {
-			currentRoles.add(((Group)o).getGroupID());
-		}
-		if (currentRoles.size() == 0) currentRoles = null;
+	List<Integer> currentRoles = null;
+	List<Group> tmp = Group.getUserGroups(ilsSession, Group.GROUPTYPE_ROLE, current.getUserProfileID());
+	if (tmp != null && !tmp.isEmpty()) {
+		currentRoles = tmp.stream().map(Group::getGroupID).collect(Collectors.toList());
+		if (currentRoles.isEmpty()) currentRoles = null;
 	}
-	Vector<Integer> currentLocations = null;
+	List<Integer> currentLocations = null;
 	tmp = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, current.getUserProfileID());
 	if (tmp != null && tmp.size() > 0) {
-		currentLocations = new Vector<Integer>();
-		for (Object o : tmp) {
-			currentLocations.add(((Group)o).getGroupID());
-		}
-		if (currentLocations.size() == 0) currentLocations = null;
+		currentLocations = tmp.stream().map(Group::getGroupID).collect(Collectors.toList());
+		if (currentLocations.isEmpty()) currentLocations = null;
 	}
 
 
@@ -100,23 +94,21 @@
 	int requestedRole = (val != null) ? (Integer.parseInt(val)) : -1;
 
 	String vals[] = request.getParameterValues("role");
-	Vector<Integer> requestedRoles = null;
+	List<Integer> requestedRoles = null;
 	if (vals != null && vals.length > 0) {
-		requestedRoles = new Vector<Integer>();
-		for (String rg : vals) {
-			try { int v = Integer.parseInt(rg); if (v > -1) requestedRoles.add(v); } catch(Exception e) {}
-		}
-		if (requestedRoles.size() == 0) requestedRoles = null;
+		requestedRoles = Arrays.stream(vals)
+			.map(s -> { try { return Integer.parseInt(s); } catch(Exception e) { return null; }})
+			.filter(i -> i != null).collect(Collectors.toList());
+		if (requestedRoles.isEmpty()) requestedRoles = null;
 	}
 
 	vals = request.getParameterValues("location");
-	Vector<Integer> requestedLocations = null;
+	List<Integer> requestedLocations = null;
 	if (vals != null && vals.length > 0) {
-		requestedLocations = new Vector<Integer>();
-		for (String rg : vals) {
-			try { int v = Integer.parseInt(rg); if (v > -1) requestedLocations.add(v); } catch(Exception e) {}
-		}
-		if (requestedLocations.size() == 0) requestedLocations = null;
+		requestedLocations = Arrays.stream(vals)
+			.map(s -> { try { return Integer.parseInt(s); } catch(Exception e) { return null; }})
+			.filter(i -> i != null).collect(Collectors.toList());
+		if (requestedLocations.isEmpty()) requestedLocations = null;
 	}
 
     if ("Save".equals(action)) {
@@ -178,6 +170,7 @@
         val = request.getParameter("firstName");
         if (val != null) current.setUserProfileFirstName(val);
         val = request.getParameter("middleName");
+logger.info("mi = " + val);
         if (val != null) current.setUserProfileMiddleName(val);
         val = request.getParameter("lastName");
         if (val != null) current.setUserProfileLastName(val);
@@ -205,6 +198,8 @@
         current.setIPRestrictOverride("true".equals(val));
         val = request.getParameter("mgrRecOver");
         current.setMgrRecurEmailOverride("true".equals(val));
+        val = request.getParameter("mgrComOver");
+        current.setMgrComplEmailOverride("true".equals(val));
         val = request.getParameter("secondValidOver");
         current.setSecondaryValidationOverride("true".equals(val));
         val = request.getParameter("hdate");
@@ -316,22 +311,16 @@
 
 	currentRoles = null;
 	tmp = Group.getUserGroups(ilsSession, Group.GROUPTYPE_ROLE, current.getUserProfileID());
-	if (tmp != null && tmp.size() > 0) {
-		currentRoles = new Vector<Integer>();
-		for (Object o : tmp) {
-			currentRoles.add(((Group)o).getGroupID());
-		}
-		if (currentRoles.size() == 0) currentRoles = null;
+	if (tmp != null && !tmp.isEmpty()) {
+		currentRoles = tmp.stream().map(Group::getGroupID).collect(Collectors.toList());
+		if (currentRoles.isEmpty()) currentRoles = null;
 	}
 
 	currentLocations = null;
 	tmp = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, current.getUserProfileID());
-	if (tmp != null && tmp.size() > 0) {
-		currentLocations = new Vector<Integer>();
-		for (Object o : tmp) {
-			currentLocations.add(((Group)o).getGroupID());
-		}
-		if (currentLocations.size() == 0) currentLocations = null;
+	if (tmp != null && !tmp.isEmpty()) {
+		currentLocations = tmp.stream().map(Group::getGroupID).collect(Collectors.toList());
+		if (currentLocations.isEmpty()) currentLocations = null;
 	}
 
             if (user.getUserProfileAccessLevel() > UserProfile.ACCESS_ANONYMOUS) {
@@ -349,13 +338,13 @@
 
     if ("SaveMgrPrivs".equals(action)) {
 
-      int p = 0;
-      String []privs = request.getParameterValues("priv");
-      if (privs != null) {
-        for (int i = 0; i < privs.length; i++) {
-          p |= Integer.parseInt(privs[i]);
-        }
-      }
+	int p = 0;
+	String []privs = request.getParameterValues("priv");
+	if (privs != null) {
+		for (String priv : privs) {
+			try { p |= Integer.parseInt(priv); } catch (Exception e) { logger.error(e); }
+		}
+	}
 
       UserProfile orig = (UserProfile)current.clone();
       current.setUserProfileAccessMode(p);
@@ -373,14 +362,17 @@
         catch (Exception e1) { logger.error(e1, e1); }
         String []mgrlocids = request.getParameterValues("mgrlocid");
         if (mgrlocids != null) {
-            for (int i = 0; i < mgrlocids.length; i++) {
-                Group.addManagerGroup(ilsSession, Integer.parseInt(mgrlocids[i]), current.getUserProfileID());
+            for (String mlid : mgrlocids) {
+		try {
+			Group.addManagerGroup(ilsSession, Integer.parseInt(mlid), current.getUserProfileID());
+		}
+		catch (Exception e) { logger.error(e); }
             }
         }
         statusMsg = "Your changes have been saved.";
     }
 
-    Vector roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
     Set<Group> locations = new HashSet<Group>();
     int limitToManager = -1;
     if (user.getUserProfileAccessLevel() <= UserProfile.ACCESS_MANAGER) {
@@ -394,7 +386,7 @@
     else {
         locations.addAll(Group.getAllGroups(ilsSession, Group.GROUPTYPE_LOCATION));
     }
-    Vector titles = Title.getAllTitles(ilsSession);
+    List<Title> titles = Title.getAllTitles(ilsSession);
     String returnPage = (user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER) ? "admin_profilemanagement.jsp" : (user.getUserProfileAccessLevel() < UserProfile.ACCESS_EMPLOYEE) ? "" : "employee.jsp";
 
     boolean editMisc = ((user.getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER) || (current.getUserProfileID() < 1) || (user.hasAccess(UserProfile.ACCESS_MODE_USERPR_MODIFY_USER)));
@@ -585,14 +577,18 @@
   </tr>
 
   <tr>
+    <td valign="middle" class="formHeadings">Override (Disable) Manager Compliance Report Emails: </td>
+    <td width="228"><input <%=(editMisc)?"":"disabled=\"true\""%> name="mgrComOver" value="true" type="checkbox" <%=current.isMgrComplEmailOverride()?"checked=\"checked\"":""%> /></td>
+  </tr>
+
+  <tr>
     <td valign="middle" class="formHeadings"><t:t>Role</t:t>: </td>
     <td width="228">
 <select id="roleSelect" multiple="multiple" <%=(editMisc)?"":"disabled=\"true\""%> name="role" style="width:215px;" data-placeholder="">
       <%
-	if (currentRoles == null) currentRoles = new Vector<Integer>();
+	if (currentRoles == null) currentRoles = new ArrayList<Integer>();
 	if (requestedRoles != null) currentRoles.addAll(requestedRoles);
-	for (int i = 0; i < roles.size(); i++) {
-		  Group role = (Group)roles.get(i);
+	for (Group role : roles) {
 %>
       <option value="<%=role.getGroupID()%>" <%=currentRoles.contains(role.getGroupID())?"selected=\"selected\"":""%>><%=HTTPUtils.canonize(role.getGroupName())%></option>
       <%
@@ -617,7 +613,7 @@
     <td>
 <select id="locationSelect" multiple="multiple" <%=(editMisc)?"":"disabled=\"true\""%> name="location" style="width:215px;" data-placeholder="">
       <%
-	if (currentLocations == null) currentLocations = new Vector<Integer>();
+	if (currentLocations == null) currentLocations = new ArrayList<Integer>();
 	if (requestedLocations != null) currentLocations.addAll(requestedLocations);
 
 	PriorityQueue<Group> sortedLocationsAll = new PriorityQueue<Group>(locations);
@@ -672,8 +668,7 @@
     <td colspan="2"><select <%=(editMisc)?"":"disabled=\"true\""%> name="empTitle" style="width:215px;">
       <option value="-1"><t:t>Select Title</t:t></option>
       <%
-     for (int i = 0; i < titles.size(); i++) {
-          Title title = (Title)titles.get(i);
+     for (Title title: titles) {
 %>
       <option value="<%=title.getTitleID()%>" <%=(title.getTitleID() == current.getUserProfileEmployeeTitleID())?"selected=\"selected\"":""%>><t:t><%=HTTPUtils.canonize(title.getTitleName())%></t:t></option>
       <%
@@ -805,9 +800,7 @@
                           <select id="defPrivsChoice" name="defPrivsChoice" onChange="setDefPrivs()">
   <option value="-1">[ Preset Permissions ]</option>
 <%
-Vector secMods = SecurityMode.getAllSecurityModes(ilsSession);
-for (int i = 0; i < secMods.size(); i++) {
-  SecurityMode s = (SecurityMode)secMods.get(i);
+for (SecurityMode s : SecurityMode.getAllSecurityModes(ilsSession)) {
   String name = s.getSecurityModeDescription();
   int value = s.getSecurityModeVal();
 %>
@@ -986,11 +979,7 @@
 			)
 		)
 	) {
-    Vector tmp2 = Group.getManagerGroups(ilsSession, Group.GROUPTYPE_LOCATION, current.getUserProfileID());
-    Vector inMgrGroup = new Vector();
-    for (int i = 0; i < tmp2.size(); i++) {
-      inMgrGroup.add(new Integer(((Group)tmp2.get(i)).getGroupID()));
-    }
+	List<Integer> inMgrGroup = Group.getManagerGroups(ilsSession, Group.GROUPTYPE_LOCATION, current.getUserProfileID()).stream().map(Group::getGroupID).collect(Collectors.toList());
 %>
 
 

Modified: trunk/webapp/admin_profilemanagement.jsp
===================================================================
--- trunk/webapp/admin_profilemanagement.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_profilemanagement.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,11 +4,14 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
 <%@ page import="java.util.Set" %>
 <%@ page import="java.util.HashSet" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.util.ArrayList" %>
+<%@ page import="java.util.Arrays" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.Map" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.lang.Comparable" %>
@@ -44,7 +47,7 @@
     	}
     }
     
-	final Vector<ReportCol> extraCols = new Vector<ReportCol>();
+	final List<ReportCol> extraCols = new ArrayList<>();
 	int k = 1;
 	while (true) {
 		String extraColName  = Utils.getSysConfig(session).getProperty("UserProfileReportExtraColumnName."+k);
@@ -57,7 +60,7 @@
 	}
 
     
-	Vector<String> hiddenCols = new Vector<String>();
+	List<String> hiddenCols = new ArrayList<>();
 	k = 1;
 	while (true) {
 		String hiddenColName  = Utils.getSysConfig(session).getProperty("UserProfileReportHiddenColumnName."+k);
@@ -68,13 +71,13 @@
 	}
 	
     int pageNum = 0;
-    Vector userProfiles = new Vector();
+    List<UserProfile> userProfiles = new ArrayList<>();
     SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
     String action = request.getParameter("action");
     String modaction = request.getParameter("modaction");
 
 
-    Vector locations = null;
+    List<Group> locations = null;
     int limitToManager = -1;
     if (user.getUserProfileAccessLevel() <= UserProfile.ACCESS_MANAGER) {
         limitToManager = user.getUserProfileID();
@@ -83,7 +86,7 @@
     else {
         locations = Group.getAllGroups(ilsSession, Group.GROUPTYPE_LOCATION);
     }
-    Vector roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
 
 
 	String tmpVals[] = request.getParameterValues("location");
@@ -139,8 +142,8 @@
              || ("Mark as Inactive".equals(modaction))) {
         String []profids = request.getParameterValues("profid");
         if (profids != null) {
-            for (int i = 0; i < profids.length; i++) {
-              UserProfile orig = UserProfile.getUserProfile(ilsSession, Integer.parseInt(profids[i]));
+            for (String pid : profids) {
+              UserProfile orig = UserProfile.getUserProfile(ilsSession, Integer.parseInt(pid));
               UserProfile mod = (UserProfile)orig.clone();
               mod.setUserProfileStatusID("Mark as Active".equals(modaction)?1:0);
               mod.save(ilsSession, orig);
@@ -161,11 +164,7 @@
     if ("Send Email To Selected Results".equals(modaction)) {
         String []profids = request.getParameterValues("profid");
         if (profids != null) {
-            Vector users = new Vector();
-            for (int i = 0; i < profids.length; i++) {
-              UserProfile u = UserProfile.getUserProfile(ilsSession, Integer.parseInt(profids[i]));
-              users.add(u);
-            }
+            List<UserProfile> users = Arrays.stream(profids).map(Integer::parseInt).map(i -> UserProfile.getUserProfile(ilsSession, i)).collect(Collectors.toList());
 	        session.setAttribute("lastDataset", users);
 	        session.setAttribute("lastDatasetType", "PMuserProfiles");
             out.print("<html><head><META HTTP-EQUIV=\"Refresh\" CONTENT=\"0;URL=admin_sendemail.jsp\"></head></html>");
@@ -182,7 +181,7 @@
         if (userProfiles != null) {
             /*
             for (int j = 0; j < userProfiles.size(); j++) {
-                UserProfile up = (UserProfile)userProfiles.get(j);
+                UserProfile up = userProfiles.get(j);
             }
             */
         }
@@ -194,7 +193,7 @@
 
     String lastDatasetType = (String)session.getAttribute("lastDatasetType");
     if ("PMuserProfiles".equals(lastDatasetType)) {
-        userProfiles = (Vector)session.getAttribute("lastDataset");
+        userProfiles = (List<UserProfile>)session.getAttribute("lastDataset");
 		final String sort = sortParam;
         if (sort != null) {
           Collections.sort(userProfiles, new Comparator() {
@@ -320,8 +319,7 @@
                               <td width="430">
                                 <select id="locationSelect" multiple="multiple" data-placeholder="Select Workgroup" name="location" size="1" style="width:274px;">
 <%
-     for (int i = 0; i < locations.size(); i++) {
-          Group location = (Group)locations.get(i);
+     for (Group location : locations) {
 %>
                                   <option value="<%=location.getGroupID()%>" <%=requestedLocations != null && requestedLocations.contains(location.getGroupID())?"selected=\"true\"":""%>><%=location.getGroupName()%><%= location.getGroupDesc().length() > 0 ? (" (" + location.getGroupDesc() + ")") : ""%></option>
 <%
@@ -334,8 +332,7 @@
                               <td>
                                 <select id="roleSelect" multiple="multiple" data-placeholder="Select Role" name="role" size="1" style="width:274px;">
 <%
-     for (int i = 0; i < roles.size(); i++) {
-          Group role = (Group)roles.get(i);
+     for (Group role : roles) {
 %>
                                   <option value="<%=role.getGroupID()%>" <%=requestedRoles != null && requestedRoles.contains(role.getGroupID())?"selected=\"true\"":""%>><%=role.getGroupName()%><%= role.getGroupDesc().length() > 0 ? (" (" + role.getGroupDesc() + ")") : ""%></option>
 <%
@@ -499,7 +496,7 @@
     int end   = begin + 25;
     if (end > userProfiles.size()) end = userProfiles.size();
     for (int j = begin; j < end; j++) {
-        UserProfile up = (UserProfile)userProfiles.get(j);
+        UserProfile up = userProfiles.get(j);
         String accessStart = "";
         String accessEnd = "";
         if (up.getUserProfileAccessLevel() == up.ACCESS_ADMIN) {

Modified: trunk/webapp/admin_resourceedit.jsp
===================================================================
--- trunk/webapp/admin_resourceedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_resourceedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,6 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.util.List" %>
 <%@ page import="java.util.Iterator" %>

Modified: trunk/webapp/admin_roleedit.jsp
===================================================================
--- trunk/webapp/admin_roleedit.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_roleedit.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,8 +4,10 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
+<%@ page import="java.util.Arrays" %>
+<%@ page import="java.util.stream.Collectors" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
 <%@ page import="java.net.URL" %>
@@ -71,9 +73,8 @@
         catch (Exception e1) { logger.error(e1, e1); }
         String []courseids = request.getParameterValues("courseid");
         if (courseids != null) {
-            for (int i = 0; i < courseids.length; i++) {
-                Group.addCourseGroup(ilsSession, current.getGroupID(), Integer.parseInt(courseids[i]));
-            }
+		final int gid = current.getGroupID();
+		Arrays.stream(courseids).map(Integer::parseInt).forEach(cid -> Group.addCourseGroup(ilsSession, gid, cid));
         }
         statusMsg = "Your changes have been saved.";
     }
@@ -127,7 +128,7 @@
 <p><br>
           <%
 if (current.getGroupID() > 0) {
-    Vector courses = Course.getAllCourses(ilsSession);
+    List<Course> courses = Course.getAllCourses(ilsSession);
 
     final String sort = request.getParameter("sort");
 
@@ -150,11 +151,7 @@
         }
     }
     courses.addAll(Course.getAllCurricula(ilsSession));
-    Vector tmp = Course.getGroupCourses(ilsSession, current.getGroupID());
-    Vector inGroup = new Vector();
-    for (int i = 0; i < tmp.size(); i++) {
-        inGroup.add(new Integer(((Course)tmp.get(i)).getCourseID()));
-    }
+    List<Integer> inGroup = Course.getGroupCourses(ilsSession, current.getGroupID()).stream().map(Course::getCourseID).collect(Collectors.toList());
 %>
                             </p>
     <form name="groupcoursesave" method="post" action="admin_roleedit.jsp">
@@ -197,7 +194,7 @@
                             </tr>
 <%
      for (int i = 0; i < courses.size(); i++) {
-          Course course = (Course)courses.get(i);
+          Course course = courses.get(i);
           boolean checked = (inGroup.contains(new Integer(course.getCourseID())));
 %>
                             <tr class="reporttxt">

Modified: trunk/webapp/admin_rolemanagement.jsp
===================================================================
--- trunk/webapp/admin_rolemanagement.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_rolemanagement.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
@@ -46,7 +46,7 @@
         }
     }
 
-    Vector roles         = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
 
     final String sort = request.getParameter("sort");
 

Modified: trunk/webapp/admin_sendemail.jsp
===================================================================
--- trunk/webapp/admin_sendemail.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_sendemail.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
@@ -40,7 +40,7 @@
   }
   
   
-     Vector userProfiles = (Vector)session.getAttribute("lastDataset");
+     List<UserProfile> userProfiles = (List<UserProfile>)session.getAttribute("lastDataset");
 
     String action    = request.getParameter("action");
     String fromEmail = request.getParameter("fromEmail"); if (fromEmail == null) fromEmail = Utils.getSysConfig(session).getProperty("SendMailFrom", ilsSession.getCurrentCompany().getCompanyAdminContactEMail());

Modified: trunk/webapp/admin_studentrecords.jsp
===================================================================
--- trunk/webapp/admin_studentrecords.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_studentrecords.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -3,7 +3,8 @@
 <%@ page trimDirectiveWhitespaces="true" %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.util.ArrayList" %>
 <%@ page import="java.util.Set" %>
 <%@ page import="java.util.HashSet" %>
 <%@ page import="java.util.Comparator" %>
@@ -46,7 +47,7 @@
        }
     }
     
-       final Vector<ReportCol> extraCols = new Vector<ReportCol>();
+       final List<ReportCol> extraCols = new ArrayList<>();
        int k = 1;
        while (true) {
                String extraColName  = Utils.getSysConfig(session).getProperty("StudentRecordsReportExtraColumnName."+k);
@@ -59,7 +60,7 @@
        }
 
     
-       Vector<String> hiddenCols = new Vector<String>();
+       List<String> hiddenCols = new ArrayList<>();
        k = 1;
        while (true) {
                String hiddenColName  = Utils.getSysConfig(session).getProperty("StudentRecordsReportHiddenColumnName."+k);
@@ -71,8 +72,8 @@
        
 
 
-    Vector userProfiles = null;
-    Vector courseAttempts = null;
+    List<UserProfile> userProfiles = null;
+    List<CourseAttempt> courseAttempts = null;
     SimpleDateFormat df  = new SimpleDateFormat("MM/dd/yyyy");
     String action = request.getParameter("action");
 
@@ -148,7 +149,7 @@
     tmp = request.getParameter("statusID");
     int statusID = (tmp == null) ? 1 : Integer.parseInt(tmp);
     int limitToManager = -1;
-    Vector locations = null;
+    List<Group> locations = null;
     if (user.getUserProfileAccessLevel() <= UserProfile.ACCESS_MANAGER) {
         limitToManager = user.getUserProfileID();
         locations = Group.getManagerGroups(ilsSession, Group.GROUPTYPE_LOCATION, limitToManager);
@@ -157,7 +158,7 @@
         locations = Group.getAllGroups(ilsSession, Group.GROUPTYPE_LOCATION);
     }
 
-    Vector roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
+    List<Group> roles = Group.getAllGroups(ilsSession, Group.GROUPTYPE_ROLE);
 
     byStudent = ((startDate == null) && (endDate == null) && (currentCourseID < 0) && (currentComplianceID < 0));
 
@@ -187,7 +188,7 @@
                 cc.copyFrom(ca);
                 UserProfile up = new UserProfile();
                 up.copyFrom(ca);
-                //Vector tmpg       = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, up.getUserProfileID());
+                //List<Group> tmpg       = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, up.getUserProfileID());
                 String upLocation = ca.getStringValue("WORKGROUP"); //((tmpg != null) && (tmpg.size()>0)) ? ((Group)tmpg.get(0)).getGroupName() : "";
                 //tmpg              = Group.getUserGroups(ilsSession, Group.GROUPTYPE_ROLE, up.getUserProfileID());
                 String upRole     = ca.getStringValue("ROLE"); //((tmpg != null) && (tmpg.size()>0)) ? ((Group)tmpg.get(0)).getGroupName() : "";
@@ -234,7 +235,7 @@
 
     String lastDatasetType = (String)session.getAttribute("lastDatasetType");
     if ("SRuserProfiles".equals(lastDatasetType)) {
-        userProfiles = (Vector)session.getAttribute("lastDataset");
+        userProfiles = (List<UserProfile>)session.getAttribute("lastDataset");
         if (sort != null) {
             Collections.sort(userProfiles, new Comparator() {
                 public int compare(Object o1, Object o2) {
@@ -287,8 +288,7 @@
         byStudent = true;
     }
     if ("SRcourseAttempts".equals(lastDatasetType)) {
-        courseAttempts = (Vector)session.getAttribute("lastDataset");
-        if (sort != null) {
+        courseAttempts = (List<CourseAttempt>)session.getAttribute("lastDataset"); if (sort != null) {
             Collections.sort(courseAttempts, new Comparator() {
                 public int compare(Object o1, Object o2) {
 			CourseAttempt ca1 = (CourseAttempt)o1;
@@ -354,7 +354,7 @@
 
 
     if (requestedLocations == null) {
-        Vector tmpg = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, user.getUserProfileID());
+        List<Group> tmpg = Group.getUserGroups(ilsSession, Group.GROUPTYPE_LOCATION, user.getUserProfileID());
         requestedLocations = ((tmpg != null) && (tmpg.size()>0))? new HashSet<Integer>(tmpg) : null;
         if (user.getUserProfileAccessLevel() >= UserProfile.ACCESS_MANAGER) {
             requestedLocations = null;
@@ -362,8 +362,8 @@
     }
 
 
-   Vector certs = Compliance.getAllCompliancies(ilsSession);
-   Vector courses = Course.getAllCourses(ilsSession);
+   List<Compliance> certs = Compliance.getAllCompliancies(ilsSession);
+   List<Course> courses = Course.getAllCourses(ilsSession);
 
     if (!noHTML) {
 %>

Modified: trunk/webapp/admin_systemmanagement.jsp
===================================================================
--- trunk/webapp/admin_systemmanagement.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/admin_systemmanagement.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -109,6 +109,10 @@
 	emailTemplates.add(new EMailTemplate("Recurrent Training Report", "Your Employee's Past Due & Upcoming Training",
 			"The attached Recurrent Training Report includes the Past Due & Upcoming Recurrent Training for your employees at {CONAME}."
 		));
+	// 8
+	emailTemplates.add(new EMailTemplate("Manager Compliance Report", "Your Teams' Compliance",
+			"The attached Team Compliance Report includes the compliance rates for your employees at {CONAME}."
+		));
 
 	Properties sysConfigProperties = Utils.getSysConfig(session);
 	File sysConfigFile = new File(session.getServletContext().getRealPath("/WEB-INF/sysconfig."+ilsSession.getCompanyID()+".properties"));
@@ -140,11 +144,20 @@
 	String currentEmailPastDueDate2 = sysConfigProperties.getProperty("EmailPastDueDate2", "");
 	String currentEmailEnableChangePassword = sysConfigProperties.getProperty("EmailEnableChangePassword", "");
 	String currentEmailEnableStudentPassFail = sysConfigProperties.getProperty("EmailEnableStudentPassFail", "");
+
 	String currentEmailEnableManagerRecurReport = sysConfigProperties.getProperty("EmailEnableManagerRecurReport", "");
 	String currentRecurReportFreq = sysConfigProperties.getProperty("RecurReportFreq", "");
 	int currentRecurReportDay = Calendar.SUNDAY; try { currentRecurReportDay = Integer.parseInt(sysConfigProperties.getProperty("RecurReportDay", "1")); } catch (Exception e) {}
 	String currentRecurReportDayOfMonth = sysConfigProperties.getProperty("RecurReportDayOfMonth", "");
 	String currentRecurReportNumDays = sysConfigProperties.getProperty("RecurReportNumDays", "");
+
+	String currentEmailEnableManagerComplReport = sysConfigProperties.getProperty("EmailEnableManagerComplReport", "");
+	String currentComplReportFreq = sysConfigProperties.getProperty("ComplReportFreq", "");
+	int currentComplReportDay = Calendar.SUNDAY; try { currentComplReportDay = Integer.parseInt(sysConfigProperties.getProperty("ComplReportDay", "1")); } catch (Exception e) {}
+	String currentComplReportDayOfMonth = sysConfigProperties.getProperty("ComplReportDayOfMonth", "");
+	String currentComplReportNumDays = sysConfigProperties.getProperty("ComplReportNumDays", "");
+	String currentComplReportThresholdPercent = sysConfigProperties.getProperty("ComplReportThresholdPercent", "");
+
 	String currentEmailEnableUserEdit = sysConfigProperties.getProperty("EmailEnableUserEdit", "");
 	String currentAPIEnable = sysConfigProperties.getProperty("APIEnable", "");
 	String currentAPICallbackCourseComplete = sysConfigProperties.getProperty("APICallbackCourseComplete", "");
@@ -210,10 +223,16 @@
     String emailEnableUserEdit = request.getParameter("emailEnableUserEdit");
     String emailEnableStudentPassFail = request.getParameter("emailEnableStudentPassFail");
     String emailEnableManagerRecurReport = request.getParameter("emailEnableManagerRecurReport");
+    String emailEnableManagerComplReport = request.getParameter("emailEnableManagerComplReport");
     String recurReportFreq = request.getParameter("recurReportFreq");
     String recurReportDay = recurReportDay = request.getParameter("recurReportDay");
     String recurReportDayOfMonth = request.getParameter("recurReportDayOfMonth");
     String recurReportNumDays = request.getParameter("recurReportNumDays");
+    String complReportFreq = request.getParameter("complReportFreq");
+    String complReportDay = complReportDay = request.getParameter("complReportDay");
+    String complReportDayOfMonth = request.getParameter("complReportDayOfMonth");
+    String complReportNumDays = request.getParameter("complReportNumDays");
+    String complReportThresholdPercent = request.getParameter("complReportThresholdPercent");
     String emailEnableBeforeDue = request.getParameter("emailEnableBeforeDue");
     String emailEnablePastDue = request.getParameter("emailEnablePastDue");
     String emailBeforeDueDate1 = request.getParameter("emailBeforeDueDate1");
@@ -319,6 +338,7 @@
                 if ("emailEnableStudentPassFail".equals(fi.getFieldName())) {
                     emailEnableStudentPassFail = fi.getString();
                 }
+
                 if ("emailEnableManagerRecurReport".equals(fi.getFieldName())) {
                     emailEnableManagerRecurReport = fi.getString();
                 }
@@ -334,6 +354,26 @@
                 if ("recurReportNumDays".equals(fi.getFieldName())) {
                     recurReportNumDays = fi.getString();
                 }
+
+                if ("emailEnableManagerComplReport".equals(fi.getFieldName())) {
+                    emailEnableManagerComplReport = fi.getString();
+                }
+                if ("complReportFreq".equals(fi.getFieldName())) {
+                    complReportFreq = fi.getString();
+                }
+                if ("complReportDay".equals(fi.getFieldName())) {
+                    complReportDay = fi.getString();
+                }
+                if ("complReportDayOfMonth".equals(fi.getFieldName())) {
+                    complReportDayOfMonth = fi.getString();
+                }
+                if ("complReportNumDays".equals(fi.getFieldName())) {
+                    complReportNumDays = fi.getString();
+                }
+                if ("complReportThresholdPercent".equals(fi.getFieldName())) {
+                    complReportThresholdPercent = fi.getString();
+                }
+
                 if ("emailEnableBeforeDue".equals(fi.getFieldName())) {
                     emailEnableBeforeDue = fi.getString();
                 }
@@ -430,6 +470,12 @@
 		statusMsg = "A test callback has been sent.";
 		logger.debug("Finished Sending test Course Attempt");
 	}
+	if ("sendMgrComplEmailsNow".equals(action)) {
+		logger.debug("Sending Manager Compliance Emails Now");
+		UserProfile.runMgrComplReport(getServletContext(), Integer.parseInt(complReportThresholdPercent), Integer.parseInt(complReportNumDays));
+		statusMsg = "Sent Manager Compliance Emails.";
+		logger.debug("Finished Sending Manager Compliance Emails");
+	}
 
     if ("Save".equals(action)) {
     	boolean saveLog = false;
@@ -616,6 +662,7 @@
         		currentSRLengthVal = srLengthVal;
         	}
         }
+
         if (recurReportFreq != null) {
         	if (!recurReportFreq.equals(currentRecurReportFreq)) {
         		saveSysconfig = true;
@@ -644,6 +691,43 @@
         		currentRecurReportNumDays = recurReportNumDays;
         	}
         }
+
+        if (complReportFreq != null) {
+        	if (!complReportFreq.equals(currentComplReportFreq)) {
+        		saveSysconfig = true;
+        		sysConfigProperties.setProperty("ComplReportFreq", complReportFreq);
+        		currentComplReportFreq = complReportFreq;
+        	}
+        }
+        if (complReportDay != null) {
+        	if (!complReportDay.equals(Integer.toString(currentComplReportDay))) {
+        		saveSysconfig = true;
+        		sysConfigProperties.setProperty("ComplReportDay", complReportDay);
+        		try { currentComplReportDay = Integer.parseInt(complReportDay); } catch(Exception e) {}
+        	}
+        }
+        if (complReportDayOfMonth != null) {
+        	if (!complReportDayOfMonth.equals(currentComplReportDayOfMonth)) {
+        		saveSysconfig = true;
+        		sysConfigProperties.setProperty("ComplReportDayOfMonth", complReportDayOfMonth);
+        		currentComplReportDayOfMonth = complReportDayOfMonth;
+        	}
+        }
+        if (complReportNumDays != null) {
+        	if (!complReportNumDays.equals(currentComplReportNumDays)) {
+        		saveSysconfig = true;
+        		sysConfigProperties.setProperty("ComplReportNumDays", complReportNumDays);
+        		currentComplReportNumDays = complReportNumDays;
+        	}
+        }
+        if (complReportThresholdPercent != null) {
+        	if (!complReportThresholdPercent.equals(currentComplReportThresholdPercent)) {
+        		saveSysconfig = true;
+        		sysConfigProperties.setProperty("ComplReportThresholdPercent", complReportThresholdPercent);
+        		currentComplReportThresholdPercent = complReportThresholdPercent;
+        	}
+        }
+
         if (alternativeLoginValidationEnable == null) { alternativeLoginValidationEnable = "off"; }
        	if (!alternativeLoginValidationEnable.equals(currentAlternativeLoginValidationEnable)) {
        		saveSysconfig = true;
@@ -742,6 +826,12 @@
        		sysConfigProperties.setProperty("EmailEnableManagerRecurReport", emailEnableManagerRecurReport);
        		currentEmailEnableManagerRecurReport = emailEnableManagerRecurReport;
        	}
+        if (emailEnableManagerComplReport == null) { emailEnableManagerComplReport = "off"; }
+       	if (!emailEnableManagerComplReport.equals(currentEmailEnableManagerComplReport)) {
+       		saveSysconfig = true;
+       		sysConfigProperties.setProperty("EmailEnableManagerComplReport", emailEnableManagerComplReport);
+       		currentEmailEnableManagerComplReport = emailEnableManagerComplReport;
+       	}
         int logSize = 0;
         int logKeep = 0;
         try { logSize = Integer.parseInt(currentLogFileSize); } catch (Exception e) {}
@@ -929,10 +1019,12 @@
 </style>
 
 <link href="lms_style.css" rel="stylesheet" type="text/css" />
+<link href="css/jquery-ui/jquery-ui.min.css" rel="stylesheet" type="text/css" />
 </head>
 
 <body onLoad="initPage()">
 <%@ include file="header.jsp" %>
+<script type="text/javascript" src="js/jquery/jquery-ui.min.js"></script>
 <script type="text/javascript">
 <!--
 function confirmSubmit(form, boxid) {
@@ -960,7 +1052,14 @@
 function initPage() {
 	setTemplateVisible(0);
 	showRecurFreqDetail();
+	showComplFreqDetail();
 	$('.recurMore').hide();
+	$('.complMore').hide();
+	$('#groupActivityDialog').dialog({
+		autoOpen : false,
+		width    : 'auto',
+		height   : '350'
+	});
 }
 
 function showRecurFreqDetail() {
@@ -977,6 +1076,22 @@
 		$('.recurDayMonth').show();
 	}
 }
+
+function showComplFreqDetail() {
+	if ($('#complReportFreq').val() == 'DAILY') {
+		$('.complDay').hide();
+		$('.complDayMonth').hide();
+	}
+	else if ($('#complReportFreq').val() == 'WEEKLY') {
+		$('.complDay').show();
+		$('.complDayMonth').hide();
+	}
+	else if ($('#complReportFreq').val() == 'MONTHLY') {
+		$('.complDay').hide();
+		$('.complDayMonth').show();
+	}
+}
+
 function showMoreRecurReport() {
 	if ($('.recurMore:first').is(":visible")) {
 		$('#moreRecurReport').html('▶ Details...');
@@ -988,6 +1103,39 @@
 	}
 }
 
+function showMoreComplReport() {
+	if ($('.complMore:first').is(":visible")) {
+		$('#moreComplReport').html('▶ Details...');
+		$('.complMore').hide();
+	}
+	else {
+		$('#moreComplReport').html('▼ Details...');
+		$('.complMore').show();
+	}
+}
+
+function runComplReport() {
+	$.post( "api/group/getactivity/", function(xml) {
+		var t = '';
+		$(xml).find('group').each(function() {
+			t += '<tr>';
+			t += '<td>' + $(this).attr('groupName') + '</td>';
+			t += '<td style="text-align:right;">' + $(this).attr('studentsTotal') + '</td>';
+			t += '<td style="text-align:right;">' + $(this).attr('studentsActive') + '</td>';
+			t += '<td><button onclick="downloadGroupComplReport(' + $(this).attr('groupID') + '); return false;">Download</button></td>';
+		});
+		$('#groupActivityTable').html(t);
+		$('#groupActivityDialog').dialog('open');
+	});
+}
+
+
+function downloadGroupComplReport(groupID) {
+	var url='api/group/getuseractivity/?format=csv&groupID='+groupID;
+	var win = window.open(url, 'getuseractivity');
+}
+
+
 // -->
 </script>
   <div id="pageContainer">
@@ -1219,7 +1367,61 @@
 	                              <td>&nbsp;</td>
 	                              <td colspan="2">&nbsp;</td>
 	                            </tr>
+
+
 	                            <tr>
+	                              <td class="formHeadings"></td>
+	                              <td colspan="2"><input name="emailEnableManagerComplReport" type="checkbox" value="on" <%="on".equals(currentEmailEnableManagerComplReport)?"checked=\"checked\"":""%> size="40"/><t:t>Manager</t:t> Compliance Report &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="cursor:pointer;" onclick="showMoreComplReport();" id="moreComplReport">▶ Details...</span></td>
+	                            </tr>
+	                            <tr class="complMore">
+					<td class="formHeadings"></td>
+					<td>Frequency: </td>
+				    </tr>
+				    <tr class="complMore">
+					<td class="formHeadings"></td>
+					<td>
+				                    <select onchange="showComplFreqDetail();" id="complReportFreq" name="complReportFreq">
+				                      <option value="DAILY" <%="DAILY".equals(currentComplReportFreq)?"selected=\"selected\"":""%>>Daily</option>
+				                      <option value="WEEKLY" <%="WEEKLY".equals(currentComplReportFreq)?"selected=\"selected\"":""%>>Weekly</option>
+				                      <option value="MONTHLY"  <%="MONTHLY".equals(currentComplReportFreq)?"selected=\"selected\"":"" %>>Monthly</option>
+				                    </select>
+					</td><td>
+						<table><tbody>
+							<tr class="complDay"><td style="text-align:center;">S</td><td style="text-align:center;">M</td><td style="text-align:center;">T</td><td style="text-align:center;">W</td><td style="text-align:center;">T</td><td style="text-align:center;">F</td><td style="text-align:center;">S</td></tr>
+							<tr>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.SUNDAY%>" <%=Calendar.SUNDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.MONDAY%>" <%=Calendar.MONDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.TUESDAY%>" <%=Calendar.TUESDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.WEDNESDAY%>" <%=Calendar.WEDNESDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.THURSDAY%>" <%=Calendar.THURSDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.FRIDAY%>" <%=Calendar.FRIDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDay"><input name="complReportDay" type="radio" value="<%=Calendar.SATURDAY%>" <%=Calendar.SATURDAY == currentComplReportDay?"checked=\"checked\"":""%>/></td>
+								<td class="complDayMonth">Send on: <input type="text" name="complReportDayOfMonth" size="2" maxlength="2" value="<%=currentComplReportDayOfMonth%>"/> Day of the Month</td>
+							</tr>
+						</tbody></table>
+					</td>
+	                            </tr>
+	                            <tr class="complMore">
+	                              <td class="formHeadings"></td>
+	                              <td colspan="2">Send to Managers Older than: <input type="text" name="complReportNumDays" value="<%=currentComplReportNumDays%>" size="4"/> Days</td>
+	                            </tr>
+	                            <tr>
+	                            <tr class="complMore">
+	                              <td class="formHeadings"></td>
+	                              <td colspan="2">If: <input type="text" name="complReportThresholdPercent" value="<%=currentComplReportThresholdPercent%>" size="4"/> Percent of Users in Workgroup have 0 Completed Courses.</td>
+	                            </tr>
+	                            <tr>
+	                            <tr class="complMore">
+	                              <td class="formHeadings"></td>
+	                              <td colspan="2">
+                                        <a href="#" onClick="runComplReport(); return false"><img style="border:0;margin:0px 3px 0px 3px;" src="images/run_btn.gif" height="24" alt=""/></a> 
+                                      </td>
+	                            </tr>
+	                            <tr>
+	                              <td>&nbsp;</td>
+	                              <td colspan="2">&nbsp;</td>
+	                            </tr>
+	                            <tr>
 	                              <td>Allow Users To Edit Their Email Address in My Profile</td>
 	                              <td colspan="2"><input name="emailEnableUserEdit" type="checkbox" value="on" <%="on".equals(currentEmailEnableUserEdit)?"checked=\"checked\"":""%> size="40"/></td>
 	                            </tr>
@@ -1576,7 +1778,22 @@
 <input name="action" value="testCallback" type="hidden"/>
 <input id="testAPICallbackCourseComplete" name="apiCallbackCourseComplete" type="hidden"/>                              </td>
 </form>
+
 </div>
+<div id="groupActivityDialog" title="Group Activity">
+<form id="testCallback" method="get" action="admin_systemmanagement.jsp">
+<input name="action" value="sendMgrComplEmailsNow" type="hidden"/>
+<button>Send All Manager Compliance Emails Now</button><br/>
+</form>
+<table>
+<thead><tr>
+<th>Group Name</th>
+<th>Total Students</th>
+<th>Active Students</th>
+</tr></thead>
+<tbody id="groupActivityTable"></tbody>
+</table>
+</div>
 
 </body>
 </html>

Modified: trunk/webapp/api/auth/session/check/index.jsp
===================================================================
--- trunk/webapp/api/auth/session/check/index.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/api/auth/session/check/index.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,30 +1,26 @@
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
 <%@ page trimDirectiveWhitespaces="true" %>
-<%@ page import="com.vidscale.udn.RightsAndRoles.User" %>
+<%@ page import="org.crosswire.webtools.RightsAndRoles" %>
+<%@ page import="org.crosswire.webtools.RightsAndRoles.User" %>
 <%@ page import="org.slf4j.LoggerFactory" %>
 <%@ page import="org.slf4j.Logger" %>
-<%@ page import="com.vidscale.udn.webtools.annotation.Description" %>
-<%@ page import="com.vidscale.udn.webtools.Parameters" %>
+<%@ page import="org.crosswire.webtools.annotation.Description" %>
+<%@ page import="org.crosswire.webtools.Parameters" %>
 <%@ page import="java.util.Optional" %>
 <%@ page import="javax.validation.constraints.NotNull" %>
-<%@ page import="com.vidscale.udn.webtools.Serializer" %>
+<%@ page import="org.crosswire.webtools.Serializer" %>
 
-<%--##########################################################################
-  # Unpublished work. Copyright 2010-2017 VidScale, Inc.                     #
-  # VIDSCALE CONFIDENTIAL                                                    #
-  #                                                                          #
-  ##########################################################################--%>
-
 <%!
+static final String sessionKeyName = RightsAndRoles.getInstance().sessionKeyName;
 static Logger logger = LoggerFactory.getLogger("session/open");
 
 @Description(value = "Check if session is established and not stale.  " +
                         "A session is opened with auth/session/open which returns" +
-                        "a udnSession token and also sets a udnSession cookie in the caller's client.  " +
-                        "The udnSession token is used throughout calls to the UDN web services API to " +
+                        "an ilsSession token and also sets a ilsSession cookie in the caller's client.  " +
+                        "The ilsSession token is used throughout calls to the UDN web services API to " +
                         "validate and identify the caller. It must be present either as " +
-                        "a cookie (udnSession), as the value of a header (X-Auth-Token) " +
-                        "or as parameter to each method (udnSession).", name = "auth/session/check")
+                        "a cookie (ilsSession), as the value of a header (X-Auth-Token) " +
+                        "or as parameter to each method (ilsSession).", name = "auth/session/check")
 public static class MyParameters extends Parameters<MyParameters> {
 	@NotNull
 	@Description(value = "pass this parameter to force usage information for this web service", defaultValue = "false", example = "true")
@@ -45,9 +41,7 @@
             }
             else if ("json".equals(params.format)) {
                 response.setContentType("application/json");
-                out.print("{ \"udnSession\":\"" + params.getUser().getSessionHash() + "\",\"user\":");
-                out.print(Serializer.toJSON(params.getUser().getJson()));
-                out.print(" }");
+                out.print(Serializer.toJSON(Serializer.fromXML(params.getUser().toString())));
                 return;
             }
             response.setContentType("text/xml");

Modified: trunk/webapp/api/auth/session/close/index.jsp
===================================================================
--- trunk/webapp/api/auth/session/close/index.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/api/auth/session/close/index.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,14 +1,8 @@
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
 <%@ page trimDirectiveWhitespaces="true" %>
-<%@ page import="com.vidscale.udn.RightsAndRoles" %>
-<%@ page import="com.vidscale.udn.RightsAndRoles.User" %>
+<%@ page import="org.crosswire.webtools.RightsAndRoles" %>
+<%@ page import="org.crosswire.webtools.RightsAndRoles.User" %>
 
-<%--##########################################################################
-  # Unpublished work. Copyright 2010-2017 VidScale, Inc.                     #
-  # VIDSCALE CONFIDENTIAL                                                    #
-  #                                                                          #
-  ##########################################################################--%>
-
 <%
     if (request.getParameter("help") == null) {
         String format = request.getParameter("format");
@@ -50,7 +44,7 @@
 <h3>Parameters</h3>
 <table border="1">
     <tr>
-        <td><b>udnSession</b></td>
+        <td><b>ilsSession</b></td>
         <td>session hash given from auth/session/open</td>
     </tr>
 </table>

Modified: trunk/webapp/api/auth/session/open/index.jsp
===================================================================
--- trunk/webapp/api/auth/session/open/index.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/api/auth/session/open/index.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,28 +1,23 @@
 <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
 <%@ page trimDirectiveWhitespaces="true" %>
-<%@ page import="com.vidscale.udn.RightsAndRoles" %>
-<%@ page import="org.slf4j.Logger" %>
-<%@ page import="org.slf4j.LoggerFactory" %>
-<%@ page import="com.vidscale.udn.webtools.Serializer" %>
-<%@ page import="com.vidscale.udn.webtools.annotation.Description" %>
-<%@ page import="com.vidscale.udn.webtools.Parameters" %>
+<%@ page import="org.crosswire.webtools.RightsAndRoles" %>
+<%@ page import="org.apache.log4j.Logger" %>
+<%@ page import="org.crosswire.webtools.Serializer" %>
+<%@ page import="org.crosswire.webtools.annotation.Description" %>
+<%@ page import="com.resolutions.ils.ILSParameters" %>
 <%@ page import="javax.validation.constraints.NotNull" %>
 <%@ page import="javax.validation.constraints.Pattern" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.util.Map" %>
 
+<%@ page import="com.resolutions.ils.data.Company" %>
 
-<%--##########################################################################
-  # Unpublished work. Copyright 2010-2017 VidScale, Inc.                     #
-  # VIDSCALE CONFIDENTIAL                                                    #
-  #                                                                          #
-  ##########################################################################--%>
-
 <%!
-    static Logger logger = LoggerFactory.getLogger("session/open");
+	static String sessionKeyName = RightsAndRoles.getInstance().sessionKeyName;
+	static Logger logger = Logger.getLogger("session/open");
 
     @Description(value = "Authenticate to the system and establish a session.  NOTE: In an effort to keep login credentials out of webserver logs, this method only accepts POST with no query string", name = "auth/session/open")
-    public static class MyParameters extends Parameters<MyParameters> {
+    public static class MyParameters extends ILSParameters<MyParameters> {
     	@NotNull
         @Description(value = "user name")
     	public String user_name;
@@ -42,24 +37,21 @@
 						addError(-2, "auth/session/open only accepts POST with no query string and not GET to discourage login credentials from ending up in server logs", 401);
 					}
 					else if (user_name != null && passwd != null) {
-						String userData = null;
-						try {
-							Map<String, String> userDataMap = new HashMap<>();
-							userDataMap.put("format", format);
-							userData = Serializer.toJSON(userDataMap);
-						}
-						catch (Exception e) {/* ignore format if we have troubles */ }
-						user = RightsAndRoles.getInstance().authenticateUser(user_name, passwd, userData);
+						Company company = Company.getCompany(request);
+						user = RightsAndRoles.getInstance().authenticateUser(company.getCompanyName()+":"+user_name, passwd);
 						if (user == null) {
-							addError(-1, "UDN web services auth/session/open: authentication failed for user: " + user_name, 401);
+							addError(-1, "ILS web services auth/session/open: authentication failed for user: " + user_name, 401);
 						}
+						else {
+							user.setDefaultFormat(format);
+						}
 					}
         }
         @Override
         protected String[] getReturns() { return new String[] {
-                "udnSession token and user object.",
-                "udnSession must be passed to other web service endpoints as either a cookie ('udnSession'), a data parameter ('udnSession'), or as an HTTP Header ('X-Auth-Token') to authenticate.",
-                "For convenience, this method will include udnSession as a cookie in the response.",
+                "" + sessionKeyName + " token and user object.",
+                "" + sessionKeyName + " must be passed to other web service endpoints as either a cookie ('" + sessionKeyName + "'), a data parameter ('" + sessionKeyName + "'), or as an HTTP Header ('X-Auth-Token') to authenticate.",
+                "For convenience, this method will include " + sessionKeyName + " as a cookie in the response.",
                 "You can check if you have an active open session using the <a href=\"../check\">auth/session/check</a> method."
         };}
         @Override
@@ -72,7 +64,7 @@
                             "<a href=\"#\" onclick=\"document.getElementById('exampleLogin').submit()\">&format=</a>" +
                             "<select name=\"format\"><option>json</option><option>xml</option></select> <button>go</button></form>",
                         "&nbsp;",
-                        "curl, json return type: <tt>curl -X POST -d 'user_name=demo at vidscale.com' -d 'passwd=demo' -d 'format=json' 'https://api.ericssonudn.com/analytics/auth/session/open/'</tt>"
+                        "curl, json return type: <tt>curl -X POST -d 'user_name=demo at ils.com' -d 'passwd=demo' -d 'format=json' '"+request.getContextPath()+"/api/auth/session/open/'</tt>"
         };}
     }
 %>
@@ -83,9 +75,9 @@
 
     if (params.getErrors().size() == 0) {
 
-            logger.info("UDN web services auth/session/open: authentication succeeded for user: " + params.user_name);
+            logger.info("ILS web services auth/session/open: authentication succeeded for user: " + params.user_name);
 
-            String sessionHash = RightsAndRoles.getInstance().openSession(params.getUser(), response);
+            String sessionHash = RightsAndRoles.getInstance().openSession(params.getILSSession(), response);
 
             if ("sessionHashOnly".equals(params.format)) {
                 response.setContentType("text/plain");
@@ -94,14 +86,12 @@
             }
             else if ("json".equals(params.format)) {
                 response.setContentType("application/json");
-                out.print("{ \"udnSession\":\"" + params.getUser().getSessionHash() + "\",\"user\":");
-                out.print(Serializer.toJSON(params.getUser().getJson()));
-                out.print(" }");
+                out.print(Serializer.toJSON(Serializer.fromXML(params.getILSSession().toString())));
                 return;
             }
             response.setContentType("text/xml");
 %>
-<%= params.getUser() %>
+<%= params.getILSSession() %>
 <%
         return;
     }

Modified: trunk/webapp/api/user/get/index.jsp
===================================================================
--- trunk/webapp/api/user/get/index.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/api/user/get/index.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -1,98 +1,77 @@
 <%@ page language="java" contentType="text/xml;charset=utf-8" %>
 <%@ page trimDirectiveWhitespaces="true" %>
-<%@ page import="com.resolutions.ils.Utils" %>
-<%@ page import="com.resolutions.ils.ILSSession" %>
-<%@ page import="com.resolutions.ils.data.UserProfile" %>
-<%@ page import="com.resolutions.ils.data.Company" %>
+<%@ page import="javax.validation.constraints.Pattern" %>
 <%@ page import="org.apache.log4j.Logger" %>
+<%@ page import="org.crosswire.webtools.annotation.*" %>
+<%@ page import="org.crosswire.webtools.Serializer" %>
+<%@ page import="com.resolutions.ils.ILSParameters" %>
+<%@ page import="com.resolutions.ils.data.UserProfile" %>
 
-<%
-	// standard service header ---------------------------------------
-	response.setContentType("text/xml");
-	int errCode = 0;
-	Company company = Company.getCompany(request);
-    
-	boolean apiEnabled = "on".equals(Utils.getSysConfig(session.getServletContext(), company.getCompanyID()).getProperty("APIEnable", "off"));
-	++errCode;
-	if (!apiEnabled) {
-		out.print("<error code=\""+errCode+"\" message=\"API not enabled in system management settings.\"/>");
-		return;
-	}
+<%!
+	@Description(value = "Retrieve a user profile record", name = "user/get")
+	public static class MyParameters extends ILSParameters<MyParameters> {
 
-	String userID = request.getParameter("ILSUSER");
-	String userPw = request.getParameter("ILSPASSWD");
-	ILSSession ilsSession = (userID != null && userPw != null)
-			? ILSSession.login(company.getCompanyName(), userID, userPw)
-			: (ILSSession)session.getAttribute("ilsSession");
-	++errCode;
-	if (ilsSession == null) {
-		out.print("<error code=\""+errCode+"\" message=\"Your iLS sign in information is not valid.\"/>");
-		return;
-	}
-	// end standard service header -----------------------------------
+		@Description(value = "User Profile ID", example = "27")
+		public Integer userProfileID = null;
+		@Description(value = "User Login ID", example = "joe at ils.com")
+		public String loginID = null;
+		@Description(value = "3rd-party supplied record identifier", example = "badgeID-4150")
+		public String userData = null;
+		@Description(value = "Detail level of result. 'extra' - includes group info", defaultValue = "complete")
+		@Pattern(regexp = "^(complete|extra)$", message = "Valid detail options: \"complete\", \"extra\".")
+		public String detail = null;
 
+		@Override
+		protected void customValidation() {
+			if (userProfileID == null && loginID == null && userData == null) {
+				addError(-101, "You need to supply at least one of userProfileID, loginID, or userData to retrieve a user");
+			}
+			if (getILSSession().getCurrentUserProfile().getUserProfileAccessLevel() <= UserProfile.ACCESS_MANAGER && !getILSSession().getCurrentUserProfile().hasAccess(UserProfile.ACCESS_MODE_USERPR_SEARCH_VIEW)) {
+				addError(-102, "Permission denied. AccessLevel: " + getILSSession().getCurrentUserProfile().getUserProfileAccessLevel());
+			}
+		}
+		private int detailLevel = UserProfile.DETAIL_COMPLETE;
+		@Override
+		protected void afterValidate() {
+			if ("extra".equals(detail)) detailLevel = UserProfile.DETAIL_EXTRA;
+		}
+		@Override
+		protected String[] getExamples() {
+		    return new String[] {
+			    "get userProfileID " + getILSSession().getUserID() + ": <a href=\"?userProfileID=" + getILSSession().getUserID() +"\">user/get/?userProfileID= "+ getILSSession().getUserID() + "</a>",
+			    "get userLoginID " + getILSSession().getUserName() + " with extra group information: <a href=\"?userProfileID=" + getILSSession().getUserID() +"&detail=extra\">user/get/?userProfileID= "+ getILSSession().getUserID() + "&detail=extra</a>",
+		    };
+		}
+		protected String[] getReturns() { return new String[] {
+				"A userProfile object"
+			};
+		}
 
-	int userProfileID  = -1; try { userProfileID = Integer.parseInt(request.getParameter("userProfileID")); } catch(Exception e) {}
-	String loginID     = request.getParameter("loginID");
-	String userData    = request.getParameter("userData");
+	}
+%>
+<%
+	MyParameters params = new MyParameters().loadFromRequest(request, response);
 
+	if (params.getErrors().isEmpty()) {
+		UserProfile foundUserProfile = null;
 
-// one of these must be supplied; otherwise, show usage info
-if (userProfileID != -1 || loginID != null || userData != null) {
-
-	Logger logger = Logger.getLogger(this.getClass());
-	Logger eventsLogger = Logger.getLogger("EVENTS");
-
-	UserProfile current = null;
-
-	++errCode;
-	if ((ilsSession.getCurrentUserProfile().getUserProfileAccessLevel() > UserProfile.ACCESS_MANAGER) || (ilsSession.getCurrentUserProfile().hasAccess(UserProfile.ACCESS_MODE_USERPR_SEARCH_VIEW))) {
-		if (userProfileID != -1) {
-			current = UserProfile.getUserProfile(ilsSession, userProfileID);
+		if (params.userProfileID != null) {
+			foundUserProfile = UserProfile.getUserProfile(params.getILSSession(), params.userProfileID);
 		}
-		else if (loginID != null) {
-			current = UserProfile.getUserProfile(ilsSession, loginID);
+		else if (params.loginID != null) {
+			foundUserProfile = UserProfile.getUserProfile(params.getILSSession(), params.loginID);
 		}
-		else if (userData != null) {
-			current = UserProfile.getUserProfileByUserData(ilsSession, userData);
+		else if (params.userData != null) {
+			foundUserProfile = UserProfile.getUserProfileByUserData(params.getILSSession(), params.userData);
 		}
+		if (foundUserProfile == null) {
+			params.addError(-103, "User Profile not found.");
+		}
+		else {
+params.getLogger().info("detaillevel: " + params.detailLevel);
+			Serializer.output(response, out, params, foundUserProfile, null, params.detailLevel);
+			return;
+		}
 	}
-	else {
-		out.print("<error code=\""+errCode+"\" message=\"Permission denied.\"/>");
-		return;
-	}
-
-	++errCode;
-	if (current == null) {
-		out.print("<error code=\""+errCode+"\" message=\"User Profile not found.\"/>");
-		return;
-	}
-
-	String detail = request.getParameter("detail");
+	Serializer.reportErrors(request, response, out, params);
 %>
-<userProfiles count="1">
-<%= current.toXML(("extra".equals(detail))?current.DETAIL_EXTRA:current.DETAIL_COMPLETE)%>
-</userProfiles>
-<%
-	return;
-}
-response.setContentType("text/html");
-%>
-<html>
-<style>th { text-align:left; }</style>
-<body>
-<h1>user/get</h1>
-<p>Retrieve a user profile record</p>
-<h3>Parameters</h3>
-<table border="1">
-<tbody>
-<tr><th>userProfileID</th><td>User Profile ID</td></tr>
-<tr><th>loginID</th><td>User Login ID</td></tr>
-<tr><th>userData</th><td>3rd-party supplied record identifier</td></tr>
-<tr><td><b>detail</b></td><td>{extra - include group info}</td></tr>
-<tr><th>ILSUSER</th><td>ILS Login Credentials. Used to validate this API request.</td></tr>
-<tr><th>ILSPASSWD</th><td>ILS Login Credentials. Used to validate this API request.</td></tr>
-</tbody>
-</table>
-</body>
-</html>

Modified: trunk/webapp/employee.jsp
===================================================================
--- trunk/webapp/employee.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/employee.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,8 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
+<%@ page import="java.util.ArrayList" %>
 <%@ page import="java.util.HashMap" %>
 <%@ page import="java.util.Collection" %>
 <%@ page import="java.util.Date" %>
@@ -36,12 +37,12 @@
     }
     openCurriculum = (String)session.getAttribute("openCurriculum");
 
-    Vector announcements = Announcement.getAllCurrentAnnouncements(ilsSession);
-    Vector resources     = Resource.getAllCurrentResources(ilsSession);
-    Collection<Course> curricula = Course.getUserCurricula(ilsSession, user.getUserProfileID());
-    Vector courses       = Course.getActiveUserCourses(ilsSession, user.getUserProfileID());
-    Vector quickViews    = Course.getUserQuickViews(ilsSession, user.getUserProfileID());
-    Vector<Integer> inCurriculum  = new Vector<Integer>();
+    List<Announcement> announcements = Announcement.getAllCurrentAnnouncements(ilsSession);
+    List<Resource> resources         = Resource.getAllCurrentResources(ilsSession);
+    Collection<Course> curricula     = Course.getUserCurricula(ilsSession, user.getUserProfileID());
+    List<Course> courses             = Course.getActiveUserCourses(ilsSession, user.getUserProfileID());
+    List<Course> quickViews          = Course.getUserQuickViews(ilsSession, user.getUserProfileID());
+    List<Integer> inCurriculum       = new ArrayList<>();
 
     // filter resource for our access level
     for (int i = 0; i < resources.size(); i++) {
@@ -92,7 +93,7 @@
 <%
     for (Course c : curricula) {
         boolean cOpen = Integer.toString(c.getCourseID()).equals(openCurriculum);
-        Vector curCourses = Course.getCurriculumCourses(ilsSession, c.getCourseID());
+        List<Course> curCourses = Course.getCurriculumCourses(ilsSession, c.getCourseID());
         if (!cOpen) {
             for (int j = 0; j < curCourses.size(); j++) {
                 Course cc = (Course)curCourses.get(j);
@@ -266,7 +267,7 @@
         boolean retake = false;
 
         Course cc         = (Course)courses.get(j);
-        Vector cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
+        List<CourseAttempt> cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
         CourseAttempt ca  = null;
         if (cas.size() == 0) {
         	// see if a past attempt exists
@@ -413,7 +414,7 @@
     for (int j = 0; j < quickViews.size(); j++) {
         boolean retake = false;
         Course cc = (Course)quickViews.get(j);
-        Vector cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
+        List<CourseAttempt> cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
         CourseAttempt ca  = null;
         if (cas.size() == 0) {
         	// see if a past attempt exists
@@ -517,10 +518,10 @@
 
 
 <%!
-public static String processCourseRow(HttpSession session, ILSSession ilsSession, UserProfile user, Course cc, Vector<Integer> inCurriculum, HashMap values, boolean supressCerts) {
+public static String processCourseRow(HttpSession session, ILSSession ilsSession, UserProfile user, Course cc, List<Integer> inCurriculum, HashMap values, boolean supressCerts) {
         boolean retake = false;
         StringBuffer out = new StringBuffer();
-        Vector cas        = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
+        List<CourseAttempt> cas = CourseAttempt.getUserCourseAttempts(ilsSession, user.getUserProfileID(), cc.getCourseID(), false);
         CourseAttempt ca  = null;
         if (cas.size() == 0) {
         	// see if a past attempt exists

Modified: trunk/webapp/manager_authorization.jsp
===================================================================
--- trunk/webapp/manager_authorization.jsp	2018-05-29 13:41:12 UTC (rev 1572)
+++ trunk/webapp/manager_authorization.jsp	2018-05-30 07:53:10 UTC (rev 1573)
@@ -4,7 +4,7 @@
 %>
 <%@ page import="com.resolutions.ils.*" %>
 <%@ page import="com.resolutions.ils.data.*" %>
-<%@ page import="java.util.Vector" %>
+<%@ page import="java.util.List" %>
 <%@ page import="java.util.Comparator" %>
 <%@ page import="java.util.Date" %>
 <%@ page import="java.io.File" %>
@@ -57,7 +57,7 @@
         }
         statusMsg = "" + caids.length + " course" + ((caids.length != 1) ? "s have" : " has") + " been approved.";
     }
-    Vector courseAttempts = CourseAttempt.getSearchUserCourseAttempts(ilsSession, -1, -1, "", "", 1, -1, null, null, limitToManager, -1, -1, null, null, true);
+    List<CourseAttempt> courseAttempts = CourseAttempt.getSearchUserCourseAttempts(ilsSession, -1, -1, "", "", 1, -1, null, null, limitToManager, -1, -1, null, null, true);
     
     
     




More information about the Ils-source mailing list