/*
*
* * Copyright (c) 2016. David Sowerby
* *
* * Licensed 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 uk.q3c.krail.core.user.profile;
import com.google.common.collect.ImmutableList;
import uk.q3c.krail.core.option.Option;
import uk.q3c.krail.core.option.OptionPermission;
import javax.annotation.Nonnull;
/**
* There are many reasons for having hierarchies which depend on some aspect of a user's profile. For example, on
* their home page, you may wish to present different company information dependent on their location, the job they
* do in the company, or both.
* <p>
* Imagine then that you have two implementations of this interface, an OrganisationHierarchy and a LocationHierarchy
* . Also imagine you have a user, Emily (userId 'equick'), a developer in Sheffield, England and Franck (userId
* 'fbaton') in the Finance team in Frankfurt, Germany.
* <p>
* Ultimately you probably want to give them the choice of what they see on their home page, but you will also want
* to set good defaults. You could use a {@link UserHierarchy} to do that in conjunction with {@link Option}
* <p>
* Initially, if option values have been set at department level, Emily would see information related to her
* development team, and information about the facilities in Sheffield, while Franck would see information related to
* Finance, and the facilities of Frankfurt.
* <p>
* When they have chosen their own options, however, that you would probably want those values to override those set at
* department level.
* <p>
* This is done by ranking the hierarchy so that in this case, the option values assigned at the user level will override any assigned at lower ranks -
* department etc. (Ranks are ordered with 0 as highest rank). Thus a 3 level hierarchy of user:department:system, user is at level 0, department at 1 and
* system at 2. The user level is considered to override that of the department, and department to override the system level.
* <p>
* How the ranks are ordered is entirely implementation dependent, but should always be returned with the user level at index 0.
* <p>
* When used with {@link Option}, there may be some option values which should be set only at the department level, for example. That is achieved simply by
* not allowing anyone access to change their own option values, and for example, only allowing those with a department admin role to change the department
* option values. This is achieved using the Shiro integration with Krail, which in turn uses {@link OptionPermission}
* <p>
* {@link UserHierarchy} implementations will often take their information from other systems - for example, an HR or
* Identity Management system may contain the Organisation hierarchy (sometimes even different ones for the same
* organisation!)
* <p>
* Implementations must be thread safe <p>
* <p>
* Created by David Sowerby on 18/02/15.
*/
public interface UserHierarchy {
/**
* Returns a list of values for the hierarchy ranks, for the current user, for this {@link UserHierarchy}
* implementation.
* <p>
* Implementations must ensure that a valid result is returned even if there is no currently authenticated user -
* that is, when the user is 'anonymous'
* <p>
* The returned list is ordered by rank, with the highest rank at index 0
*
* @return a list of String identifiers for this hierarchy, for the current user, ordered by rank, with the highest
* rank at index 0.
*/
@Nonnull
ImmutableList<String> ranksForCurrentUser();
/**
* The name to be used when for this hierarchy when stored in persistence (which should not therefore change, or
* values will be lost)
*
* @return The name to be used when for this hierarchy when stored in persistence (which should not therefore
* change, or values will be lost)
*/
default String persistenceName() {
return this.getClass()
.getSimpleName();
}
/**
* The descriptive name for this hierarchy, usually for use in the user interface. Should be Locale sensitive
*
* @return The descriptive name for this hierarchy, usually for use in the user interface. Should be Locale
* sensitive
*/
String displayName();
/**
* Returns the identifier of the {@code hierarchyRank}, for the current user. From the example above that could
* be 'Development' if an implementation represented an Organisation, and the current user is Emily
*
* @param hierarchyRank
* the rank (index) which is required.
*
* @return the layer, for the current user, at the rank specified by {@code hierarchyRank}.
*
* @throws IllegalArgumentException
* if {@code hierarchyRank} is out of bounds
*/
String rankName(int hierarchyRank);
/**
* Returns the name of the highest rank for this hierarchy - usually the user id if the user is logged in
*
* @return the name of the highest rank for this hierarchy - usually the user id if the user is logged in
*/
String highestRankName();
/**
* Returns the name of the lowest rank for this hierarchy - usually 'system' or something similar.
*
* @return the name of the lowest rank for this hierarchy - usually 'system' or something similar.
*/
String lowestRankName();
/**
* Returns the lowest rank index in the hierarchy (which will be the highest numeric value)
*
* @return the lowest rank index in the hierarchy (which will be the highest numeric value)
*/
int lowestRank();
}