GUACAMOLE-394: Add user history REST endpoint.
Project: http://git-wip-us.apache.org/repos/asf/guacamole-client/repo Commit: http://git-wip-us.apache.org/repos/asf/guacamole-client/commit/29284725 Tree: http://git-wip-us.apache.org/repos/asf/guacamole-client/tree/29284725 Diff: http://git-wip-us.apache.org/repos/asf/guacamole-client/diff/29284725 Branch: refs/heads/master Commit: 2928472549e5664247ff892d9155ddca8c9365b5 Parents: 9df20f2 Author: Michael Jumper <mjum...@apache.org> Authored: Mon Sep 11 18:27:21 2017 -0700 Committer: Michael Jumper <mjum...@apache.org> Committed: Mon Dec 11 20:44:28 2017 -0800 ---------------------------------------------------------------------- .../rest/history/APIActivityRecord.java | 131 +++++++++++++++++ .../rest/history/APIConnectionRecord.java | 89 +----------- .../APIConnectionRecordSortPredicate.java | 144 ------------------- .../rest/history/APISortPredicate.java | 144 +++++++++++++++++++ .../guacamole/rest/history/HistoryResource.java | 60 +++++++- 5 files changed, 335 insertions(+), 233 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/29284725/guacamole/src/main/java/org/apache/guacamole/rest/history/APIActivityRecord.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/history/APIActivityRecord.java b/guacamole/src/main/java/org/apache/guacamole/rest/history/APIActivityRecord.java new file mode 100644 index 0000000..c1a0149 --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/history/APIActivityRecord.java @@ -0,0 +1,131 @@ +/* + * 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.rest.history; + +import java.util.Date; +import org.apache.guacamole.net.auth.ActivityRecord; + +/** + * A activity record which may be exposed through the REST endpoints. + */ +public class APIActivityRecord { + + /** + * The date and time the activity began. + */ + private final Date startDate; + + /** + * The date and time the activity ended, or null if the activity is + * still in progress or if the end time is unknown. + */ + private final Date endDate; + + /** + * The hostname or IP address of the remote host that performed the + * activity associated with this record, if known. + */ + private final String remoteHost; + + /** + * The name of the user who performed or is performing the activity + * associated with this record. + */ + private final String username; + + /** + * Whether the activity is still in progress. + */ + private final boolean active; + + /** + * Creates a new APIActivityRecord, copying the data from the given activity + * record. + * + * @param record + * The record to copy data from. + */ + public APIActivityRecord(ActivityRecord record) { + this.startDate = record.getStartDate(); + this.endDate = record.getEndDate(); + this.remoteHost = record.getRemoteHost(); + this.username = record.getUsername(); + this.active = record.isActive(); + } + + /** + * Returns the date and time the activity began. + * + * @return + * The date and time the activity began. + */ + public Date getStartDate() { + return startDate; + } + + /** + * Returns the date and time the activity ended, if applicable. + * + * @return + * The date and time the activity ended, or null if the activity is + * still in progress or if the end time is unknown. + */ + public Date getEndDate() { + return endDate; + } + + /** + * Returns the hostname or IP address of the remote host that performed the + * activity associated with this record, if known. + * + * @return + * The hostname or IP address of the remote host that performed the + * activity associated with this record, or null if the remote host is + * unknown. + */ + public String getRemoteHost() { + return remoteHost; + } + + /** + * Returns the name of the user who performed or is performing the activity + * associated with this record. + * + * @return + * The name of the user who performed or is performing the activity + * associated with this record. + */ + public String getUsername() { + return username; + } + + /** + * Returns whether the activity associated with this record is still in + * progress. + * + * @return + * true if the activity associated with this record is still in + * progress, false otherwise. + */ + public boolean isActive() { + return active; + } + +} http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/29284725/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecord.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecord.java b/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecord.java index 97c99a0..9d17fbf 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecord.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecord.java @@ -19,13 +19,12 @@ package org.apache.guacamole.rest.history; -import java.util.Date; import org.apache.guacamole.net.auth.ConnectionRecord; /** * A connection record which may be exposed through the REST endpoints. */ -public class APIConnectionRecord { +public class APIConnectionRecord extends APIActivityRecord { /** * The identifier of the connection associated with this record. @@ -48,32 +47,6 @@ public class APIConnectionRecord { private final String sharingProfileName; /** - * The date and time the connection began. - */ - private final Date startDate; - - /** - * The date and time the connection ended, or null if the connection is - * still running or if the end time is unknown. - */ - private final Date endDate; - - /** - * The host from which the connection originated, if known. - */ - private final String remoteHost; - - /** - * The name of the user who used or is using the connection. - */ - private final String username; - - /** - * Whether the connection is currently active. - */ - private final boolean active; - - /** * Creates a new APIConnectionRecord, copying the data from the given * record. * @@ -81,15 +54,11 @@ public class APIConnectionRecord { * The record to copy data from. */ public APIConnectionRecord(ConnectionRecord record) { + super(record); this.connectionIdentifier = record.getConnectionIdentifier(); this.connectionName = record.getConnectionName(); this.sharingProfileIdentifier = record.getSharingProfileIdentifier(); this.sharingProfileName = record.getSharingProfileName(); - this.startDate = record.getStartDate(); - this.endDate = record.getEndDate(); - this.remoteHost = record.getRemoteHost(); - this.username = record.getUsername(); - this.active = record.isActive(); } /** @@ -139,58 +108,4 @@ public class APIConnectionRecord { return sharingProfileName; } - /** - * Returns the date and time the connection began. - * - * @return - * The date and time the connection began. - */ - public Date getStartDate() { - return startDate; - } - - /** - * Returns the date and time the connection ended, if applicable. - * - * @return - * The date and time the connection ended, or null if the connection is - * still running or if the end time is unknown. - */ - public Date getEndDate() { - return endDate; - } - - /** - * Returns the remote host from which this connection originated. - * - * @return - * The remote host from which this connection originated. - */ - public String getRemoteHost() { - return remoteHost; - } - - /** - * Returns the name of the user who used or is using the connection at the - * times given by this connection record. - * - * @return - * The name of the user who used or is using the associated connection. - */ - public String getUsername() { - return username; - } - - /** - * Returns whether the connection associated with this record is still - * active. - * - * @return - * true if the connection associated with this record is still active, - * false otherwise. - */ - public boolean isActive() { - return active; - } - } http://git-wip-us.apache.org/repos/asf/guacamole-client/blob/29284725/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecordSortPredicate.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecordSortPredicate.java b/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecordSortPredicate.java deleted file mode 100644 index d2281d0..0000000 --- a/guacamole/src/main/java/org/apache/guacamole/rest/history/APIConnectionRecordSortPredicate.java +++ /dev/null @@ -1,144 +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.rest.history; - -import javax.ws.rs.core.Response; -import org.apache.guacamole.GuacamoleClientException; -import org.apache.guacamole.net.auth.ActivityRecordSet; -import org.apache.guacamole.rest.APIException; - -/** - * A sort predicate which species the property to use when sorting connection - * records, along with the sort order. - */ -public class APIConnectionRecordSortPredicate { - - /** - * The prefix which will be included before the name of a sortable property - * to indicate that the sort order is descending, not ascending. - */ - public static final String DESCENDING_PREFIX = "-"; - - /** - * All possible property name strings and their corresponding - * ActivityRecordSet.SortableProperty values. - */ - public enum SortableProperty { - - /** - * The date that the connection associated with the connection record - * began (connected). - */ - startDate(ActivityRecordSet.SortableProperty.START_DATE); - - /** - * The ActivityRecordSet.SortableProperty that this property name - * string represents. - */ - public final ActivityRecordSet.SortableProperty recordProperty; - - /** - * Creates a new SortableProperty which associates the property name - * string (identical to its own name) with the given - * ActivityRecordSet.SortableProperty value. - * - * @param recordProperty - * The ActivityRecordSet.SortableProperty value to associate with - * the new SortableProperty. - */ - SortableProperty(ActivityRecordSet.SortableProperty recordProperty) { - this.recordProperty = recordProperty; - } - - } - - /** - * The property to use when sorting ConnectionRecords. - */ - private ActivityRecordSet.SortableProperty property; - - /** - * Whether the requested sort order is descending (true) or ascending - * (false). - */ - private boolean descending; - - /** - * Parses the given string value, determining the requested sort property - * and ordering. Possible values consist of any valid property name, and - * may include an optional prefix to denote descending sort order. Each - * possible property name is enumerated by the SortableValue enum. - * - * @param value - * The sort predicate string to parse, which must consist ONLY of a - * valid property name, possibly preceded by the DESCENDING_PREFIX. - * - * @throws APIException - * If the provided sort predicate string is invalid. - */ - public APIConnectionRecordSortPredicate(String value) - throws APIException { - - // Parse whether sort order is descending - if (value.startsWith(DESCENDING_PREFIX)) { - descending = true; - value = value.substring(DESCENDING_PREFIX.length()); - } - - // Parse sorting property into ActivityRecordSet.SortableProperty - try { - this.property = SortableProperty.valueOf(value).recordProperty; - } - - // Bail out if sort property is not valid - catch (IllegalArgumentException e) { - throw new APIException( - Response.Status.BAD_REQUEST, - new GuacamoleClientException(String.format("Invalid sort property: \"%s\"", value)) - ); - } - - } - - /** - * Returns the SortableProperty defined by ActivityRecordSet which - * represents the property requested. - * - * @return - * The ActivityRecordSet.SortableProperty which refers to the same - * property as the string originally provided when this - * APIConnectionRecordSortPredicate was created. - */ - public ActivityRecordSet.SortableProperty getProperty() { - return property; - } - - /** - * Returns whether the requested 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/29284725/guacamole/src/main/java/org/apache/guacamole/rest/history/APISortPredicate.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/history/APISortPredicate.java b/guacamole/src/main/java/org/apache/guacamole/rest/history/APISortPredicate.java new file mode 100644 index 0000000..c45ae9a --- /dev/null +++ b/guacamole/src/main/java/org/apache/guacamole/rest/history/APISortPredicate.java @@ -0,0 +1,144 @@ +/* + * 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.rest.history; + +import javax.ws.rs.core.Response; +import org.apache.guacamole.GuacamoleClientException; +import org.apache.guacamole.net.auth.ActivityRecordSet; +import org.apache.guacamole.rest.APIException; + +/** + * A sort predicate which species the property to use when sorting activity + * records, along with the sort order. + */ +public class APISortPredicate { + + /** + * The prefix which will be included before the name of a sortable property + * to indicate that the sort order is descending, not ascending. + */ + public static final String DESCENDING_PREFIX = "-"; + + /** + * All possible property name strings and their corresponding + * ActivityRecordSet.SortableProperty values. + */ + public enum SortableProperty { + + /** + * The date that the activity associated with the activity record + * began. + */ + startDate(ActivityRecordSet.SortableProperty.START_DATE); + + /** + * The ActivityRecordSet.SortableProperty that this property name + * string represents. + */ + public final ActivityRecordSet.SortableProperty recordProperty; + + /** + * Creates a new SortableProperty which associates the property name + * string (identical to its own name) with the given + * ActivityRecordSet.SortableProperty value. + * + * @param recordProperty + * The ActivityRecordSet.SortableProperty value to associate with + * the new SortableProperty. + */ + SortableProperty(ActivityRecordSet.SortableProperty recordProperty) { + this.recordProperty = recordProperty; + } + + } + + /** + * The property to use when sorting ActivityRecords. + */ + private ActivityRecordSet.SortableProperty property; + + /** + * Whether the requested sort order is descending (true) or ascending + * (false). + */ + private boolean descending; + + /** + * Parses the given string value, determining the requested sort property + * and ordering. Possible values consist of any valid property name, and + * may include an optional prefix to denote descending sort order. Each + * possible property name is enumerated by the SortableValue enum. + * + * @param value + * The sort predicate string to parse, which must consist ONLY of a + * valid property name, possibly preceded by the DESCENDING_PREFIX. + * + * @throws APIException + * If the provided sort predicate string is invalid. + */ + public APISortPredicate(String value) + throws APIException { + + // Parse whether sort order is descending + if (value.startsWith(DESCENDING_PREFIX)) { + descending = true; + value = value.substring(DESCENDING_PREFIX.length()); + } + + // Parse sorting property into ActivityRecordSet.SortableProperty + try { + this.property = SortableProperty.valueOf(value).recordProperty; + } + + // Bail out if sort property is not valid + catch (IllegalArgumentException e) { + throw new APIException( + Response.Status.BAD_REQUEST, + new GuacamoleClientException(String.format("Invalid sort property: \"%s\"", value)) + ); + } + + } + + /** + * Returns the SortableProperty defined by ActivityRecordSet which + * represents the property requested. + * + * @return + * The ActivityRecordSet.SortableProperty which refers to the same + * property as the string originally provided when this + * APISortPredicate was created. + */ + public ActivityRecordSet.SortableProperty getProperty() { + return property; + } + + /** + * Returns whether the requested 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/29284725/guacamole/src/main/java/org/apache/guacamole/rest/history/HistoryResource.java ---------------------------------------------------------------------- diff --git a/guacamole/src/main/java/org/apache/guacamole/rest/history/HistoryResource.java b/guacamole/src/main/java/org/apache/guacamole/rest/history/HistoryResource.java index 53a8cdb..559ebd5 100644 --- a/guacamole/src/main/java/org/apache/guacamole/rest/history/HistoryResource.java +++ b/guacamole/src/main/java/org/apache/guacamole/rest/history/HistoryResource.java @@ -28,6 +28,7 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.ActivityRecord; import org.apache.guacamole.net.auth.ActivityRecordSet; import org.apache.guacamole.net.auth.ConnectionRecord; import org.apache.guacamole.net.auth.UserContext; @@ -88,7 +89,7 @@ public class HistoryResource { @Path("connections") public List<APIConnectionRecord> getConnectionHistory( @QueryParam("contains") List<String> requiredContents, - @QueryParam("order") List<APIConnectionRecordSortPredicate> sortPredicates) + @QueryParam("order") List<APISortPredicate> sortPredicates) throws GuacamoleException { // Retrieve overall connection history @@ -101,7 +102,7 @@ public class HistoryResource { } // Sort according to specified ordering - for (APIConnectionRecordSortPredicate predicate : sortPredicates) + for (APISortPredicate predicate : sortPredicates) history = history.sort(predicate.getProperty(), predicate.isDescending()); // Limit to maximum result size @@ -117,4 +118,59 @@ public class HistoryResource { } + /** + * Retrieves the login history for all users, restricted by optional filter + * parameters. + * + * @param requiredContents + * The set of strings that each must occur somewhere within the + * returned user records, whether within the associated username or any + * associated date. If non-empty, any user record not matching each of + * the strings within the collection will be excluded from the results. + * + * @param sortPredicates + * A list of predicates to apply while sorting the resulting user + * records, describing the properties involved and the sort order for + * those properties. + * + * @return + * A list of user records, describing the start and end times of user + * sessions. + * + * @throws GuacamoleException + * If an error occurs while retrieving the user history. + */ + @GET + @Path("users") + public List<APIActivityRecord> getUserHistory( + @QueryParam("contains") List<String> requiredContents, + @QueryParam("order") List<APISortPredicate> sortPredicates) + throws GuacamoleException { + + // Retrieve overall user history + ActivityRecordSet<ActivityRecord> history = userContext.getUserHistory(); + + // Restrict to records which contain the specified strings + for (String required : requiredContents) { + if (!required.isEmpty()) + history = history.contains(required); + } + + // Sort according to specified ordering + for (APISortPredicate predicate : sortPredicates) + history = history.sort(predicate.getProperty(), predicate.isDescending()); + + // Limit to maximum result size + history = history.limit(MAXIMUM_HISTORY_SIZE); + + // Convert record set to collection of API user records + List<APIActivityRecord> apiRecords = new ArrayList<APIActivityRecord>(); + for (ActivityRecord record : history.asCollection()) + apiRecords.add(new APIActivityRecord(record)); + + // Return the converted history + return apiRecords; + + } + }