You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@guacamole.apache.org by vn...@apache.org on 2018/01/05 15:40:49 UTC

[02/16] guacamole-client git commit: GUACAMOLE-394: Split ConnectionRecord model and ModeledConnectionRecord into ActivityRecordModel and ModeledActivityRecord, etc. mirroring changes to guacamole-ext.

GUACAMOLE-394: Split ConnectionRecord model and ModeledConnectionRecord into ActivityRecordModel and ModeledActivityRecord, etc. mirroring changes to guacamole-ext.

Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/c991ea46
Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/c991ea46
Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/c991ea46

Branch: refs/heads/staging/0.9.14
Commit: c991ea46bc406dbf3973ebffb7a374e71379229e
Parents: 3d7b8ee
Author: Michael Jumper <mj...@apache.org>
Authored: Tue Sep 12 12:18:05 2017 -0700
Committer: Michael Jumper <mj...@apache.org>
Committed: Mon Dec 11 23:51:56 2017 -0800

----------------------------------------------------------------------
 .../auth/jdbc/base/ActivityRecordModel.java     | 167 +++++++++++
 .../jdbc/base/ActivityRecordSearchTerm.java     | 291 +++++++++++++++++++
 .../jdbc/base/ActivityRecordSortPredicate.java  |  77 +++++
 .../auth/jdbc/base/ModeledActivityRecord.java   |  73 +++++
 .../jdbc/connection/ConnectionRecordMapper.java |  10 +-
 .../jdbc/connection/ConnectionRecordModel.java  | 135 +--------
 .../connection/ConnectionRecordSearchTerm.java  | 291 -------------------
 .../jdbc/connection/ConnectionRecordSet.java    |  14 +-
 .../ConnectionRecordSortPredicate.java          |  77 -----
 .../auth/jdbc/connection/ConnectionService.java |   6 +-
 .../connection/ModeledConnectionRecord.java     |  31 +-
 11 files changed, 632 insertions(+), 540 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
new file mode 100644
index 0000000..86f2204
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordModel.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import java.util.Date;
+
+/**
+ * A single activity record representing an arbitrary activity performed by a
+ * user.
+ */
+public class ActivityRecordModel {
+
+    /**
+     * The database ID of the user associated with this activity record.
+     */
+    private Integer userID;
+
+    /**
+     * The username of the user that performed the activity.
+     */
+    private String username;
+
+    /**
+     * The remote host associated with the user that performed the activity.
+     */
+    private String remoteHost;
+
+    /**
+     * The time the activity was initiated by the associated user.
+     */
+    private Date startDate;
+
+    /**
+     * The time the activity ended, or null if the end time is not known or
+     * the activity is still in progress.
+     */
+    private Date endDate;
+
+    /**
+     * Returns the database ID of the user associated with this activity
+     * record.
+     * 
+     * @return
+     *     The database ID of the user associated with this activity record.
+     */
+    public Integer getUserID() {
+        return userID;
+    }
+
+    /**
+     * Sets the database ID of the user associated with this activity record.
+     *
+     * @param userID
+     *     The database ID of the user to associate with this activity
+     *     record.
+     */
+    public void setUserID(Integer userID) {
+        this.userID = userID;
+    }
+
+    /**
+     * Returns the username of the user that performed the activity associated
+     * with this record.
+     * 
+     * @return
+     *     The username of the user that performed the activity associated with
+     *     this record.
+     */
+    public String getUsername() {
+        return username;
+    }
+
+    /**
+     * Sets the username of the user that performed the activity associated
+     * with this record.
+     *
+     * @param username
+     *     The username of the user that performed the activity associated with
+     *     this record.
+     */
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    /**
+     * Returns the remote host associated with the user that performed the
+     * activity.
+     *
+     * @return
+     *     The remote host associated with the user that performed the activity.
+     */
+    public String getRemoteHost() {
+        return remoteHost;
+    }
+
+    /**
+     * Sets the remote host associated with the user that performed the
+     * activity.
+     *
+     * @param remoteHost
+     *     The remote host associated with the user that performed the activity.
+     */
+    public void setRemoteHost(String remoteHost) {
+        this.remoteHost = remoteHost;
+    }
+
+    /**
+     * Returns the time the activity was initiated by the associated user.
+     *
+     * @return
+     *     The time the activity was initiated by the associated user.
+     */
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    /**
+     * Sets the time the activity was initiated by the associated user.
+     *
+     * @param startDate
+     *     The time the activity was initiated by the associated user.
+     */
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    /**
+     * Returns the time the activity ended, or null if the end time is not
+     * known or the activity is still in progress.
+     *
+     * @return
+     *     The time the activity ended, or null if the end time is not known or
+     *     the activity is still in progress.
+     */
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    /**
+     * Sets the time the activity ended, if known.
+     *
+     * @param endDate
+     *     The time the activity ended, or null if the end time is not known or
+     *     the activity is still in progress.
+     */
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
new file mode 100644
index 0000000..54af1a6
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSearchTerm.java
@@ -0,0 +1,291 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A search term for querying historical records of arbitrary activities. This
+ * will contain a the search term in string form and, if that string appears to
+ * be a date. a corresponding date range.
+ */
+public class ActivityRecordSearchTerm {
+    
+    /**
+     * A pattern that can match a year, year and month, or year and month and
+     * day.
+     */
+    private static final Pattern DATE_PATTERN = 
+            Pattern.compile("(\\d+)(?:-(\\d+)?(?:-(\\d+)?)?)?");
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * year number.
+     */
+    private static final int YEAR_GROUP = 1;
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * month number, if any.
+     */
+    private static final int MONTH_GROUP = 2;
+
+    /**
+     * The index of the group within <code>DATE_PATTERN</code> containing the
+     * day number, if any.
+     */
+    private static final int DAY_GROUP = 3;
+
+    /**
+     * The start of the date range for records that should be retrieved, if the
+     * provided search term appears to be a date.
+     */
+    private final Date startDate;
+    
+    /**
+     * The end of the date range for records that should be retrieved, if the
+     * provided search term appears to be a date.
+     */
+    private final Date endDate;
+    
+    /**
+     * The string that should be searched for.
+     */
+    private final String term;
+    
+    /**
+     * Parse the given string as an integer, returning the provided default
+     * value if the string is null.
+     * 
+     * @param str
+     *     The string to parse as an integer.
+     *
+     * @param defaultValue
+     *     The value to return if <code>str</code> is null.
+     * 
+     * @return
+     *     The parsed value, or the provided default value if <code>str</code>
+     *     is null.
+     */
+    private static int parseInt(String str, int defaultValue) {
+        
+        if (str == null)
+            return defaultValue;
+        
+        return Integer.parseInt(str);
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * year as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the year whose end (last millisecond) is to be
+     *     returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same year as
+     *     <code>calendar</code>.
+     */
+    private static Calendar getEndOfYear(Calendar calendar) {
+
+        // Get first day of next year
+        Calendar endOfYear = Calendar.getInstance();
+        endOfYear.clear();
+        endOfYear.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
+
+        // Transform into the last millisecond of the given year
+        endOfYear.add(Calendar.MILLISECOND, -1);
+
+        return endOfYear;
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * month and year as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the month and year whose end (last millisecond) 
+     *     is to be returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same month 
+     *     and year as <code>calendar</code>.
+     */
+    private static Calendar getEndOfMonth(Calendar calendar) {
+
+        // Copy given calender only up to given month
+        Calendar endOfMonth = Calendar.getInstance();
+        endOfMonth.clear();
+        endOfMonth.set(Calendar.YEAR,  calendar.get(Calendar.YEAR));
+        endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
+
+        // Advance to the last millisecond of the given month
+        endOfMonth.add(Calendar.MONTH,        1);
+        endOfMonth.add(Calendar.MILLISECOND, -1);
+
+        return endOfMonth;
+
+    }
+    
+    /**
+     * Returns a new calendar representing the last millisecond of the same
+     * year, month, and day as <code>calendar</code>.
+     * 
+     * @param calendar
+     *     The calendar defining the year, month, and day whose end 
+     *     (last millisecond) is to be returned.
+     *
+     * @return
+     *     A new calendar representing the last millisecond of the same year, 
+     *     month, and day as <code>calendar</code>.
+     */
+    private static Calendar getEndOfDay(Calendar calendar) {
+
+        // Copy given calender only up to given month
+        Calendar endOfMonth = Calendar.getInstance();
+        endOfMonth.clear();
+        endOfMonth.set(Calendar.YEAR,         calendar.get(Calendar.YEAR));
+        endOfMonth.set(Calendar.MONTH,        calendar.get(Calendar.MONTH));
+        endOfMonth.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
+
+        // Advance to the last millisecond of the given day
+        endOfMonth.add(Calendar.DAY_OF_MONTH, 1);
+        endOfMonth.add(Calendar.MILLISECOND, -1);
+
+        return endOfMonth;
+
+    }
+
+    /**
+     * Creates a new ActivityRecordSearchTerm representing the given string.
+     * If the given string appears to be a date, the start and end dates of the
+     * implied date range will be automatically determined and made available
+     * via getStartDate() and getEndDate() respectively.
+     *
+     * @param term
+     *     The string that should be searched for.
+     */
+    public ActivityRecordSearchTerm(String term) {
+
+        // Search terms absolutely must not be null
+        if (term == null)
+            throw new NullPointerException("Search terms may not be null");
+
+        this.term = term;
+
+        // Parse start/end of date range if term appears to be a date
+        Matcher matcher = DATE_PATTERN.matcher(term);
+        if (matcher.matches()) {
+
+            // Retrieve date components from term
+            String year  = matcher.group(YEAR_GROUP);
+            String month = matcher.group(MONTH_GROUP);
+            String day   = matcher.group(DAY_GROUP);
+            
+            // Parse start date from term
+            Calendar startCalendar = Calendar.getInstance();
+            startCalendar.clear();
+            startCalendar.set(
+                Integer.parseInt(year),
+                parseInt(month, 1) - 1,
+                parseInt(day,   1)
+            );
+
+            Calendar endCalendar;
+
+            // Derive end date from start date
+            if (month == null) {
+                endCalendar = getEndOfYear(startCalendar);
+            }
+            else if (day == null) {
+                endCalendar = getEndOfMonth(startCalendar);
+            }
+            else {
+                endCalendar = getEndOfDay(startCalendar);
+            }
+
+            // Convert results back into dates
+            this.startDate = startCalendar.getTime();
+            this.endDate   = endCalendar.getTime();
+            
+        }
+
+        // The search term doesn't look like a date
+        else {
+            this.startDate = null;
+            this.endDate   = null;
+        }
+
+    }
+
+    /**
+     * Returns the start of the date range for records that should be retrieved, 
+     * if the provided search term appears to be a date.
+     * 
+     * @return
+     *     The start of the date range.
+     */
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    /**
+     * Returns the end of the date range for records that should be retrieved, 
+     * if the provided search term appears to be a date.
+     * 
+     * @return
+     *     The end of the date range.
+     */
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    /**
+     * Returns the string that should be searched for.
+     * 
+     * @return
+     *     The search term.
+     */
+    public String getTerm() {
+        return term;
+    }
+
+    @Override
+    public int hashCode() {
+        return term.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+
+        if (obj == null || !(obj instanceof ActivityRecordSearchTerm))
+            return false;
+
+        return ((ActivityRecordSearchTerm) obj).getTerm().equals(getTerm());
+
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
new file mode 100644
index 0000000..ab0d3ce
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ActivityRecordSortPredicate.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+import org.apache.guacamole.net.auth.ActivityRecordSet;
+
+/**
+ * A sort predicate which species the property to use when sorting activity
+ * records, along with the sort order.
+ */
+public class ActivityRecordSortPredicate {
+
+    /**
+     * The property to use when sorting ActivityRecords.
+     */
+    private final ActivityRecordSet.SortableProperty property;
+
+    /**
+     * Whether the sort order is descending (true) or ascending (false).
+     */
+    private final boolean descending;
+    
+    /**
+     * Creates a new ActivityRecordSortPredicate with the given sort property
+     * and sort order.
+     * 
+     * @param property 
+     *     The property to use when sorting ActivityRecords.
+     * 
+     * @param descending 
+     *     Whether the sort order is descending (true) or ascending (false).
+     */
+    public ActivityRecordSortPredicate(ActivityRecordSet.SortableProperty property,
+            boolean descending) {
+        this.property   = property;
+        this.descending = descending;
+    }
+    
+    /**
+     * Returns the property that should be used when sorting ActivityRecords.
+     *
+     * @return
+     *     The property that should be used when sorting ActivityRecords.
+     */
+    public ActivityRecordSet.SortableProperty getProperty() {
+        return property;
+    }
+
+    /**
+     * Returns whether the sort order is descending.
+     *
+     * @return
+     *     true if the sort order is descending, false if the sort order is
+     *     ascending.
+     */
+    public boolean isDescending() {
+        return descending;
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
new file mode 100644
index 0000000..95b1a25
--- /dev/null
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/base/ModeledActivityRecord.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.jdbc.base;
+
+
+import java.util.Date;
+import org.apache.guacamole.net.auth.ActivityRecord;
+
+/**
+ * An ActivityRecord which is backed by a database model.
+ */
+public class ModeledActivityRecord implements ActivityRecord {
+
+    /**
+     * The model object backing this activity record.
+     */
+    private final ActivityRecordModel model;
+
+    /**
+     * Creates a new ModeledActivityRecord backed by the given model object.
+     * Changes to this record will affect the backing model object, and changes
+     * to the backing model object will affect this record.
+     * 
+     * @param model
+     *     The model object to use to back this activity record.
+     */
+    public ModeledActivityRecord(ActivityRecordModel model) {
+        this.model = model;
+    }
+
+    @Override
+    public Date getStartDate() {
+        return model.getStartDate();
+    }
+
+    @Override
+    public Date getEndDate() {
+        return model.getEndDate();
+    }
+
+    @Override
+    public String getRemoteHost() {
+        return model.getRemoteHost();
+    }
+
+    @Override
+    public String getUsername() {
+        return model.getUsername();
+    }
+
+    @Override
+    public boolean isActive() {
+        return false;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
index aefff92..637fd0f 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordMapper.java
@@ -21,6 +21,8 @@ package org.apache.guacamole.auth.jdbc.connection;
 
 import java.util.Collection;
 import java.util.List;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.ibatis.annotations.Param;
 import org.apache.guacamole.auth.jdbc.user.UserModel;
 
@@ -75,8 +77,8 @@ public interface ConnectionRecordMapper {
      * @return
      *     The results of the search performed with the given parameters.
      */
-    List<ConnectionRecordModel> search(@Param("terms") Collection<ConnectionRecordSearchTerm> terms,
-            @Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
+    List<ConnectionRecordModel> search(@Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
             @Param("limit") int limit);
 
     /**
@@ -104,8 +106,8 @@ public interface ConnectionRecordMapper {
      *     The results of the search performed with the given parameters.
      */
     List<ConnectionRecordModel> searchReadable(@Param("user") UserModel user,
-            @Param("terms") Collection<ConnectionRecordSearchTerm> terms,
-            @Param("sortPredicates") List<ConnectionRecordSortPredicate> sortPredicates,
+            @Param("terms") Collection<ActivityRecordSearchTerm> terms,
+            @Param("sortPredicates") List<ActivityRecordSortPredicate> sortPredicates,
             @Param("limit") int limit);
 
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
index f142f4e..29c5556 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordModel.java
@@ -19,14 +19,14 @@
 
 package org.apache.guacamole.auth.jdbc.connection;
 
-import java.util.Date;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordModel;
 
 /**
  * A single connection record representing a past usage of a particular
  * connection. If the connection was being shared, the sharing profile used to
  * join the connection is included in the record.
  */
-public class ConnectionRecordModel {
+public class ConnectionRecordModel extends ActivityRecordModel {
 
     /**
      * The identifier of the connection associated with this connection record.
@@ -54,32 +54,6 @@ public class ConnectionRecordModel {
     private String sharingProfileName;
 
     /**
-     * The database ID of the user associated with this connection record.
-     */
-    private Integer userID;
-
-    /**
-     * The username of the user associated with this connection record.
-     */
-    private String username;
-
-    /**
-     * The remote host associated with this connection record.
-     */
-    private String remoteHost;
-
-    /**
-     * The time the connection was initiated by the associated user.
-     */
-    private Date startDate;
-
-    /**
-     * The time the connection ended, or null if the end time is not known or
-     * the connection is still running.
-     */
-    private Date endDate;
-
-    /**
      * Returns the identifier of the connection associated with this connection
      * record.
      *
@@ -179,109 +153,4 @@ public class ConnectionRecordModel {
         this.sharingProfileName = sharingProfileName;
     }
 
-    /**
-     * Returns the database ID of the user associated with this connection
-     * record.
-     * 
-     * @return
-     *     The database ID of the user associated with this connection record.
-     */
-    public Integer getUserID() {
-        return userID;
-    }
-
-    /**
-     * Sets the database ID of the user associated with this connection record.
-     *
-     * @param userID
-     *     The database ID of the user to associate with this connection
-     *     record.
-     */
-    public void setUserID(Integer userID) {
-        this.userID = userID;
-    }
-
-    /**
-     * Returns the username of the user associated with this connection record.
-     * 
-     * @return
-     *     The username of the user associated with this connection record.
-     */
-    public String getUsername() {
-        return username;
-    }
-
-    /**
-     * Sets the username of the user associated with this connection record.
-     *
-     * @param username
-     *     The username of the user to associate with this connection record.
-     */
-    public void setUsername(String username) {
-        this.username = username;
-    }
-
-    /**
-     * Returns the remote host associated with this connection record.
-     *
-     * @return
-     *     The remote host associated with this connection record.
-     */
-    public String getRemoteHost() {
-        return remoteHost;
-    }
-
-    /**
-     * Sets the remote host associated with this connection record.
-     *
-     * @param remoteHost
-     *     The remote host to associate with this connection record.
-     */
-    public void setRemoteHost(String remoteHost) {
-        this.remoteHost = remoteHost;
-    }
-
-    /**
-     * Returns the date that the associated connection was established.
-     *
-     * @return
-     *     The date the associated connection was established.
-     */
-    public Date getStartDate() {
-        return startDate;
-    }
-
-    /**
-     * Sets the date that the associated connection was established.
-     *
-     * @param startDate
-     *     The date that the associated connection was established.
-     */
-    public void setStartDate(Date startDate) {
-        this.startDate = startDate;
-    }
-
-    /**
-     * Returns the date that the associated connection ended, or null if no
-     * end date was recorded. The lack of an end date does not necessarily
-     * mean that the connection is still active.
-     *
-     * @return
-     *     The date the associated connection ended, or null if no end date was
-     *     recorded.
-     */
-    public Date getEndDate() {
-        return endDate;
-    }
-
-    /**
-     * Sets the date that the associated connection ended.
-     *
-     * @param endDate
-     *     The date that the associated connection ended.
-     */
-    public void setEndDate(Date endDate) {
-        this.endDate = endDate;
-    }
-
 }

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
deleted file mode 100644
index 844eff7..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSearchTerm.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.connection;
-
-import java.util.Calendar;
-import java.util.Date;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * A search term for querying historical connection records. This will contain
- * a the search term in string form and, if that string appears to be a date. a
- * corresponding date range.
- */
-public class ConnectionRecordSearchTerm {
-    
-    /**
-     * A pattern that can match a year, year and month, or year and month and
-     * day.
-     */
-    private static final Pattern DATE_PATTERN = 
-            Pattern.compile("(\\d+)(?:-(\\d+)?(?:-(\\d+)?)?)?");
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * year number.
-     */
-    private static final int YEAR_GROUP = 1;
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * month number, if any.
-     */
-    private static final int MONTH_GROUP = 2;
-
-    /**
-     * The index of the group within <code>DATE_PATTERN</code> containing the
-     * day number, if any.
-     */
-    private static final int DAY_GROUP = 3;
-
-    /**
-     * The start of the date range for records that should be retrieved, if the
-     * provided search term appears to be a date.
-     */
-    private final Date startDate;
-    
-    /**
-     * The end of the date range for records that should be retrieved, if the
-     * provided search term appears to be a date.
-     */
-    private final Date endDate;
-    
-    /**
-     * The string that should be searched for.
-     */
-    private final String term;
-    
-    /**
-     * Parse the given string as an integer, returning the provided default
-     * value if the string is null.
-     * 
-     * @param str
-     *     The string to parse as an integer.
-     *
-     * @param defaultValue
-     *     The value to return if <code>str</code> is null.
-     * 
-     * @return
-     *     The parsed value, or the provided default value if <code>str</code>
-     *     is null.
-     */
-    private static int parseInt(String str, int defaultValue) {
-        
-        if (str == null)
-            return defaultValue;
-        
-        return Integer.parseInt(str);
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * year as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the year whose end (last millisecond) is to be
-     *     returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same year as
-     *     <code>calendar</code>.
-     */
-    private static Calendar getEndOfYear(Calendar calendar) {
-
-        // Get first day of next year
-        Calendar endOfYear = Calendar.getInstance();
-        endOfYear.clear();
-        endOfYear.set(Calendar.YEAR, calendar.get(Calendar.YEAR) + 1);
-
-        // Transform into the last millisecond of the given year
-        endOfYear.add(Calendar.MILLISECOND, -1);
-
-        return endOfYear;
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * month and year as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the month and year whose end (last millisecond) 
-     *     is to be returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same month 
-     *     and year as <code>calendar</code>.
-     */
-    private static Calendar getEndOfMonth(Calendar calendar) {
-
-        // Copy given calender only up to given month
-        Calendar endOfMonth = Calendar.getInstance();
-        endOfMonth.clear();
-        endOfMonth.set(Calendar.YEAR,  calendar.get(Calendar.YEAR));
-        endOfMonth.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
-
-        // Advance to the last millisecond of the given month
-        endOfMonth.add(Calendar.MONTH,        1);
-        endOfMonth.add(Calendar.MILLISECOND, -1);
-
-        return endOfMonth;
-
-    }
-    
-    /**
-     * Returns a new calendar representing the last millisecond of the same
-     * year, month, and day as <code>calendar</code>.
-     * 
-     * @param calendar
-     *     The calendar defining the year, month, and day whose end 
-     *     (last millisecond) is to be returned.
-     *
-     * @return
-     *     A new calendar representing the last millisecond of the same year, 
-     *     month, and day as <code>calendar</code>.
-     */
-    private static Calendar getEndOfDay(Calendar calendar) {
-
-        // Copy given calender only up to given month
-        Calendar endOfMonth = Calendar.getInstance();
-        endOfMonth.clear();
-        endOfMonth.set(Calendar.YEAR,         calendar.get(Calendar.YEAR));
-        endOfMonth.set(Calendar.MONTH,        calendar.get(Calendar.MONTH));
-        endOfMonth.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
-
-        // Advance to the last millisecond of the given day
-        endOfMonth.add(Calendar.DAY_OF_MONTH, 1);
-        endOfMonth.add(Calendar.MILLISECOND, -1);
-
-        return endOfMonth;
-
-    }
-
-    /**
-     * Creates a new ConnectionRecordSearchTerm representing the given string.
-     * If the given string appears to be a date, the start and end dates of the
-     * implied date range will be automatically determined and made available
-     * via getStartDate() and getEndDate() respectively.
-     *
-     * @param term
-     *     The string that should be searched for.
-     */
-    public ConnectionRecordSearchTerm(String term) {
-
-        // Search terms absolutely must not be null
-        if (term == null)
-            throw new NullPointerException("Search terms may not be null");
-
-        this.term = term;
-
-        // Parse start/end of date range if term appears to be a date
-        Matcher matcher = DATE_PATTERN.matcher(term);
-        if (matcher.matches()) {
-
-            // Retrieve date components from term
-            String year  = matcher.group(YEAR_GROUP);
-            String month = matcher.group(MONTH_GROUP);
-            String day   = matcher.group(DAY_GROUP);
-            
-            // Parse start date from term
-            Calendar startCalendar = Calendar.getInstance();
-            startCalendar.clear();
-            startCalendar.set(
-                Integer.parseInt(year),
-                parseInt(month, 1) - 1,
-                parseInt(day,   1)
-            );
-
-            Calendar endCalendar;
-
-            // Derive end date from start date
-            if (month == null) {
-                endCalendar = getEndOfYear(startCalendar);
-            }
-            else if (day == null) {
-                endCalendar = getEndOfMonth(startCalendar);
-            }
-            else {
-                endCalendar = getEndOfDay(startCalendar);
-            }
-
-            // Convert results back into dates
-            this.startDate = startCalendar.getTime();
-            this.endDate   = endCalendar.getTime();
-            
-        }
-
-        // The search term doesn't look like a date
-        else {
-            this.startDate = null;
-            this.endDate   = null;
-        }
-
-    }
-
-    /**
-     * Returns the start of the date range for records that should be retrieved, 
-     * if the provided search term appears to be a date.
-     * 
-     * @return
-     *     The start of the date range.
-     */
-    public Date getStartDate() {
-        return startDate;
-    }
-
-    /**
-     * Returns the end of the date range for records that should be retrieved, 
-     * if the provided search term appears to be a date.
-     * 
-     * @return
-     *     The end of the date range.
-     */
-    public Date getEndDate() {
-        return endDate;
-    }
-
-    /**
-     * Returns the string that should be searched for.
-     * 
-     * @return
-     *     The search term.
-     */
-    public String getTerm() {
-        return term;
-    }
-
-    @Override
-    public int hashCode() {
-        return term.hashCode();
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-
-        if (obj == null || !(obj instanceof ConnectionRecordSearchTerm))
-            return false;
-
-        return ((ConnectionRecordSearchTerm) obj).getTerm().equals(getTerm());
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
index 7b3d629..df2a0a9 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSet.java
@@ -26,6 +26,8 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.guacamole.auth.jdbc.base.RestrictedObject;
 import org.apache.guacamole.net.auth.ActivityRecordSet;
 import org.apache.guacamole.net.auth.ActivityRecordSet.SortableProperty;
@@ -52,8 +54,8 @@ public class ConnectionRecordSet extends RestrictedObject
      * connection record not matching each of the strings within the collection 
      * will be excluded from the results.
      */
-    private final Set<ConnectionRecordSearchTerm> requiredContents = 
-            new HashSet<ConnectionRecordSearchTerm>();
+    private final Set<ActivityRecordSearchTerm> requiredContents =
+            new HashSet<ActivityRecordSearchTerm>();
     
     /**
      * The maximum number of connection history records that should be returned
@@ -66,8 +68,8 @@ public class ConnectionRecordSet extends RestrictedObject
      * records, describing the properties involved and the sort order for those 
      * properties.
      */
-    private final List<ConnectionRecordSortPredicate> connectionRecordSortPredicates =
-            new ArrayList<ConnectionRecordSortPredicate>();
+    private final List<ActivityRecordSortPredicate> connectionRecordSortPredicates =
+            new ArrayList<ActivityRecordSortPredicate>();
     
     @Override
     public Collection<ConnectionRecord> asCollection()
@@ -79,7 +81,7 @@ public class ConnectionRecordSet extends RestrictedObject
     @Override
     public ConnectionRecordSet contains(String value)
             throws GuacamoleException {
-        requiredContents.add(new ConnectionRecordSearchTerm(value));
+        requiredContents.add(new ActivityRecordSearchTerm(value));
         return this;
     }
 
@@ -93,7 +95,7 @@ public class ConnectionRecordSet extends RestrictedObject
     public ConnectionRecordSet sort(SortableProperty property, boolean desc)
             throws GuacamoleException {
         
-        connectionRecordSortPredicates.add(new ConnectionRecordSortPredicate(
+        connectionRecordSortPredicates.add(new ActivityRecordSortPredicate(
             property,
             desc
         ));

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
deleted file mode 100644
index 69eee78..0000000
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionRecordSortPredicate.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.guacamole.auth.jdbc.connection;
-
-import org.apache.guacamole.net.auth.ActivityRecordSet;
-
-/**
- * A sort predicate which species the property to use when sorting connection
- * records, along with the sort order.
- */
-public class ConnectionRecordSortPredicate {
-
-    /**
-     * The property to use when sorting ConnectionRecords.
-     */
-    private final ActivityRecordSet.SortableProperty property;
-
-    /**
-     * Whether the sort order is descending (true) or ascending (false).
-     */
-    private final boolean descending;
-    
-    /**
-     * Creates a new ConnectionRecordSortPredicate with the given sort property 
-     * and sort order.
-     * 
-     * @param property 
-     *     The property to use when sorting ConnectionRecords.
-     * 
-     * @param descending 
-     *     Whether the sort order is descending (true) or ascending (false).
-     */
-    public ConnectionRecordSortPredicate(ActivityRecordSet.SortableProperty property,
-            boolean descending) {
-        this.property   = property;
-        this.descending = descending;
-    }
-    
-    /**
-     * Returns the property that should be used when sorting ConnectionRecords.
-     *
-     * @return
-     *     The property that should be used when sorting ConnectionRecords.
-     */
-    public ActivityRecordSet.SortableProperty getProperty() {
-        return property;
-    }
-
-    /**
-     * Returns whether the sort order is descending.
-     *
-     * @return
-     *     true if the sort order is descending, false if the sort order is
-     *     ascending.
-     */
-    public boolean isDescending() {
-        return descending;
-    }
-    
-}

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
index f256324..983f395 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ConnectionService.java
@@ -34,6 +34,8 @@ import org.apache.guacamole.auth.jdbc.tunnel.GuacamoleTunnelService;
 import org.apache.guacamole.GuacamoleClientException;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.GuacamoleSecurityException;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSearchTerm;
+import org.apache.guacamole.auth.jdbc.base.ActivityRecordSortPredicate;
 import org.apache.guacamole.auth.jdbc.base.ModeledChildDirectoryObjectService;
 import org.apache.guacamole.auth.jdbc.permission.ConnectionPermissionMapper;
 import org.apache.guacamole.auth.jdbc.permission.ObjectPermissionMapper;
@@ -460,8 +462,8 @@ public class ConnectionService extends ModeledChildDirectoryObjectService<Modele
      *     If permission to read the connection history is denied.
      */
     public List<ConnectionRecord> retrieveHistory(ModeledAuthenticatedUser user,
-            Collection<ConnectionRecordSearchTerm> requiredContents,
-            List<ConnectionRecordSortPredicate> sortPredicates, int limit)
+            Collection<ActivityRecordSearchTerm> requiredContents,
+            List<ActivityRecordSortPredicate> sortPredicates, int limit)
             throws GuacamoleException {
 
         List<ConnectionRecordModel> searchResults;

http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/c991ea46/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
----------------------------------------------------------------------
diff --git a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
index a5e83d4..9f34385 100644
--- a/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
+++ b/extensions/guacamole-auth-jdbc/modules/guacamole-auth-jdbc-base/src/main/java/org/apache/guacamole/auth/jdbc/connection/ModeledConnectionRecord.java
@@ -20,13 +20,14 @@
 package org.apache.guacamole.auth.jdbc.connection;
 
 
-import java.util.Date;
+import org.apache.guacamole.auth.jdbc.base.ModeledActivityRecord;
 import org.apache.guacamole.net.auth.ConnectionRecord;
 
 /**
  * A ConnectionRecord which is backed by a database model.
  */
-public class ModeledConnectionRecord implements ConnectionRecord {
+public class ModeledConnectionRecord extends ModeledActivityRecord
+        implements ConnectionRecord {
 
     /**
      * The model object backing this connection record.
@@ -42,6 +43,7 @@ public class ModeledConnectionRecord implements ConnectionRecord {
      *     The model object to use to back this connection record.
      */
     public ModeledConnectionRecord(ConnectionRecordModel model) {
+        super(model);
         this.model = model;
     }
 
@@ -65,29 +67,4 @@ public class ModeledConnectionRecord implements ConnectionRecord {
         return model.getSharingProfileName();
     }
 
-    @Override
-    public Date getStartDate() {
-        return model.getStartDate();
-    }
-
-    @Override
-    public Date getEndDate() {
-        return model.getEndDate();
-    }
-
-    @Override
-    public String getRemoteHost() {
-        return model.getRemoteHost();
-    }
-
-    @Override
-    public String getUsername() {
-        return model.getUsername();
-    }
-
-    @Override
-    public boolean isActive() {
-        return false;
-    }
-
 }