GUACAMOLE-220: Refactor default behavior of SimpleUser and SimpleUserGroup into AbstractUser and AbstractUserGroup.
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java
index 2dae702..0a1acbf 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUser.java
@@ -19,10 +19,17 @@
 
 package org.apache.guacamole.net.auth;
 
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
 
 /**
- * Basic implementation of a Guacamole user which uses the username to
- * determine equality. Username comparison is case-sensitive.
+ * Base implementation of User which provides default implementations of
+ * most functions.
  */
 public abstract class AbstractUser extends AbstractIdentifiable
         implements User {
@@ -44,4 +51,164 @@
         this.password = password;
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty map. Implementations
+     * that wish to expose custom attributes should override this function.
+     */
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.<String, String>emptyMap();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply ignores all attributes given.
+     * Implementations that wish to support modification of custom attributes
+     * should override this function.
+     */
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+        // Ignore all attributes by default
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply returns {@code null}. Implementations that
+     * wish to expose the date and time that a user was last active should
+     * override this function.
+     */
+    @Override
+    public Date getLastActive() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty list. Implementations
+     * that wish to expose user login history should override this function.
+     */
+    @Override
+    public List<ActivityRecord> getHistory() throws GuacamoleException {
+        return Collections.<ActivityRecord>emptyList();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public SystemPermissionSet getSystemPermissions()
+            throws GuacamoleException {
+        return SystemPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getConnectionPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getConnectionGroupPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getUserPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getUserGroupPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getActiveConnectionPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getSharingProfilePermissions() {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty related object set.
+     * Implementations that wish to expose group membership should override
+     * this function.
+     */
+    @Override
+    public RelatedObjectSet getUserGroups() throws GuacamoleException {
+        return RelatedObjectSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply returns {@code this}. Implementations that
+     * wish to expose permissions which apply indirectly (such as through
+     * group inheritance) should override this function.
+     */
+    @Override
+    public Permissions getEffectivePermissions() throws GuacamoleException {
+        return this;
+    }
+
 }
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserGroup.java
new file mode 100644
index 0000000..725984d
--- /dev/null
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/AbstractUserGroup.java
@@ -0,0 +1,183 @@
+/*
+ * 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.net.auth;
+
+import java.util.Collections;
+import java.util.Map;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
+import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
+
+/**
+ * Base implementation of UserGroup which provides default implementations of
+ * most functions.
+ */
+public class AbstractUserGroup extends AbstractIdentifiable implements UserGroup {
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty map. Implementations
+     * that wish to expose custom attributes should override this function.
+     */
+    @Override
+    public Map<String, String> getAttributes() {
+        return Collections.<String, String>emptyMap();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply ignores all attributes given.
+     * Implementations that wish to support modification of custom attributes
+     * should override this function.
+     */
+    @Override
+    public void setAttributes(Map<String, String> attributes) {
+        // Ignore all attributes by default
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public SystemPermissionSet getSystemPermissions()
+            throws GuacamoleException {
+        return SystemPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getConnectionPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getConnectionGroupPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getUserPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getUserGroupPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getActiveConnectionPermissions()
+            throws GuacamoleException {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty permission set.
+     * Implementations that wish to expose permissions should override this
+     * function.
+     */
+    @Override
+    public ObjectPermissionSet getSharingProfilePermissions() {
+        return ObjectPermissionSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty related object set.
+     * Implementations that wish to expose group membership should override
+     * this function.
+     */
+    @Override
+    public RelatedObjectSet getUserGroups() throws GuacamoleException {
+        return RelatedObjectSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty related object set.
+     * Implementations that wish to expose group membership should override
+     * this function.
+     */
+    @Override
+    public RelatedObjectSet getMemberUsers() throws GuacamoleException {
+        return RelatedObjectSet.EMPTY_SET;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation simply an immutable, empty related object set.
+     * Implementations that wish to expose group membership should override
+     * this function.
+     */
+    @Override
+    public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
+        return RelatedObjectSet.EMPTY_SET;
+    }
+
+}
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUser.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUser.java
index d85cc97..8e349e2 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUser.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUser.java
@@ -20,20 +20,12 @@
 package org.apache.guacamole.net.auth.simple;
 
 import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
 import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
 import java.util.Set;
 import org.apache.guacamole.GuacamoleException;
 import org.apache.guacamole.net.auth.AbstractUser;
-import org.apache.guacamole.net.auth.ActivityRecord;
-import org.apache.guacamole.net.auth.Permissions;
-import org.apache.guacamole.net.auth.RelatedObjectSet;
 import org.apache.guacamole.net.auth.permission.ObjectPermission;
 import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
-import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
 
 /**
  * A read-only User implementation which has no permissions. Implementations
@@ -70,10 +62,7 @@
      *     The username to assign to this SimpleUser.
      */
     public SimpleUser(String username) {
-
-        // Set username
         super.setIdentifier(username);
-
     }
 
     /**
@@ -173,32 +162,6 @@
     }
 
     @Override
-    public Map<String, String> getAttributes() {
-        return Collections.<String, String>emptyMap();
-    }
-
-    @Override
-    public void setAttributes(Map<String, String> attributes) {
-        // Do nothing - there are no attributes
-    }
-
-    @Override
-    public Date getLastActive() {
-        return null;
-    }
-
-    @Override
-    public List<ActivityRecord> getHistory() throws GuacamoleException {
-        return Collections.<ActivityRecord>emptyList();
-    }
-
-    @Override
-    public SystemPermissionSet getSystemPermissions()
-            throws GuacamoleException {
-        return SystemPermissionSet.EMPTY_SET;
-    }
-
-    @Override
     public ObjectPermissionSet getConnectionPermissions()
             throws GuacamoleException {
         return new SimpleObjectPermissionSet(connectionPermissions);
@@ -216,31 +179,4 @@
         return new SimpleObjectPermissionSet(userPermissions);
     }
 
-    @Override
-    public ObjectPermissionSet getUserGroupPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getActiveConnectionPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getSharingProfilePermissions() {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public RelatedObjectSet getUserGroups() throws GuacamoleException {
-        return RelatedObjectSet.EMPTY_SET;
-    }
-
-    @Override
-    public Permissions getEffectivePermissions() throws GuacamoleException {
-        return this;
-    }
-
 }
diff --git a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserGroup.java b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserGroup.java
index 77b3741..be52d16 100644
--- a/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserGroup.java
+++ b/guacamole-ext/src/main/java/org/apache/guacamole/net/auth/simple/SimpleUserGroup.java
@@ -19,21 +19,14 @@
 
 package org.apache.guacamole.net.auth.simple;
 
-import java.util.Collections;
-import java.util.Map;
-import org.apache.guacamole.GuacamoleException;
-import org.apache.guacamole.net.auth.AbstractIdentifiable;
-import org.apache.guacamole.net.auth.RelatedObjectSet;
-import org.apache.guacamole.net.auth.UserGroup;
-import org.apache.guacamole.net.auth.permission.ObjectPermissionSet;
-import org.apache.guacamole.net.auth.permission.SystemPermissionSet;
+import org.apache.guacamole.net.auth.AbstractUserGroup;
 
 /**
  * A read-only UserGroup implementation which has no members and no
  * permissions. Implementations that need to define members or permissions
  * should extend this class and override the associated getters.
  */
-public class SimpleUserGroup extends AbstractIdentifiable implements UserGroup {
+public class SimpleUserGroup extends AbstractUserGroup {
 
     /**
      * Creates a completely uninitialized SimpleUserGroup.
@@ -51,70 +44,4 @@
         super.setIdentifier(identifier);
     }
 
-    @Override
-    public Map<String, String> getAttributes() {
-        return Collections.<String, String>emptyMap();
-    }
-
-    @Override
-    public void setAttributes(Map<String, String> attributes) {
-        // Do nothing - there are no attributes
-    }
-
-    @Override
-    public SystemPermissionSet getSystemPermissions()
-            throws GuacamoleException {
-        return SystemPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getConnectionPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getConnectionGroupPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getUserPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getUserGroupPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getActiveConnectionPermissions()
-            throws GuacamoleException {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public ObjectPermissionSet getSharingProfilePermissions() {
-        return ObjectPermissionSet.EMPTY_SET;
-    }
-
-    @Override
-    public RelatedObjectSet getUserGroups() throws GuacamoleException {
-        return RelatedObjectSet.EMPTY_SET;
-    }
-
-    @Override
-    public RelatedObjectSet getMemberUsers() throws GuacamoleException {
-        return RelatedObjectSet.EMPTY_SET;
-    }
-
-    @Override
-    public RelatedObjectSet getMemberUserGroups() throws GuacamoleException {
-        return RelatedObjectSet.EMPTY_SET;
-    }
-
 }