/*
*
* * 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.persist.cache.option;
import uk.q3c.krail.core.option.Option;
import uk.q3c.krail.core.option.OptionKey;
import uk.q3c.krail.core.user.profile.RankOption;
import uk.q3c.krail.core.user.profile.UserHierarchy;
import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Provides a unique identifier for cached {@link Option}
* <p>
* Created by David Sowerby on 19/02/15.
*/
@Immutable
public class OptionCacheKey<T> {
private final UserHierarchy hierarchy;
private final String requestedRankName;
private final OptionKey<T> optionKey;
private final RankOption rankOption;
/**
* Calls {@link OptionCacheKey#OptionCacheKey(UserHierarchy, RankOption, int, OptionKey)} with the the lowest rank where rankOption is
* {@link RankOption#LOWEST_RANK}, otherwie is called with rank of 0
*/
public OptionCacheKey(@Nonnull UserHierarchy hierarchy, @Nonnull RankOption rankOption, @Nonnull OptionKey<T> optionKey) {
this(hierarchy, rankOption, rankOption == RankOption.LOWEST_RANK ? hierarchy.lowestRank() : 0, optionKey);
}
/**
* @param rankOption determines whether this key represents the lowest or highest in a hierarchy, or a specific rank
* @param hierarchy the hierarchy to use
* @param requestedRank which rank to look for - only required if {@code rankOption} is {@link RankOption#SPECIFIC_RANK}, for
* {@link RankOption#HIGHEST_RANK} or {@link RankOption#LOWEST_RANK} use the alternative constructor:
* {@link OptionCacheKey#OptionCacheKey(UserHierarchy, RankOption, OptionKey)}
* @param optionKey an object representing a unique key for the option within its context
*/
public OptionCacheKey(@Nonnull UserHierarchy hierarchy, @Nonnull RankOption rankOption, int requestedRank, @Nonnull OptionKey<T> optionKey) {
checkNotNull(hierarchy);
checkNotNull(rankOption);
checkNotNull(optionKey);
checkArgument(requestedRank >= 0);
this.rankOption = rankOption;
this.hierarchy = hierarchy;
this.requestedRankName = hierarchy.rankName(requestedRank);
this.optionKey = optionKey;
}
/**
* Constructs a copy with rank and RankOption changed
*
* @param cacheKey the key to copy
* @param rank the new rank
* @param rankOption the #rankOption to set
*/
public OptionCacheKey(@Nonnull OptionCacheKey<T> cacheKey, int rank, @Nonnull RankOption rankOption) {
this(cacheKey.getHierarchy(), rankOption, rank, cacheKey.getOptionKey());
}
/**
* copy constructor which changes the RankOption to {@code rankOption}
*
* @param cacheKey the key to copy
* @param rankOption the new rankOption to use
*/
public OptionCacheKey(@Nonnull OptionCacheKey<T> cacheKey, @Nonnull RankOption rankOption) {
checkNotNull(cacheKey);
checkNotNull(rankOption);
this.rankOption = rankOption;
this.hierarchy = cacheKey.getHierarchy();
this.requestedRankName = cacheKey.getRequestedRankName();
this.optionKey = cacheKey.getOptionKey();
}
/**
* Constructs a copy with {@link #requestedRankName} changed to {@code rankName}. The {@link #rankOption} may be forced to {@link
* RankOption#SPECIFIC_RANK}
* with {@code makeSpecific}
*
* @param cacheKey the key to copy
* @param rankName the new rank name
* @param rankOption the #rankOption to set
*/
public OptionCacheKey(@Nonnull OptionCacheKey<T> cacheKey, @Nonnull String rankName, @Nonnull RankOption rankOption) {
checkNotNull(cacheKey);
checkNotNull(rankName);
checkNotNull(rankOption);
this.requestedRankName = rankName;
this.optionKey = cacheKey.getOptionKey();
this.hierarchy = cacheKey.getHierarchy();
this.rankOption = rankOption;
}
public UserHierarchy getHierarchy() {
return hierarchy;
}
public OptionKey<T> getOptionKey() {
return optionKey;
}
public String getRequestedRankName() {
return requestedRankName;
}
public RankOption getRankOption() {
return rankOption;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof OptionCacheKey)) {
return false;
}
OptionCacheKey<?> that = (OptionCacheKey) o;
if (!hierarchy.equals(that.hierarchy)) {
return false;
}
if (!optionKey.equals(that.optionKey)) {
return false;
}
if (rankOption != that.rankOption) {
return false;
}
//if a SPECIFIC, we need to compare the rank name as well
if (rankOption == RankOption.SPECIFIC_RANK) {
return requestedRankName.equals(that.requestedRankName);
} else {
return true;
}
}
@Override
public int hashCode() {
int result = hierarchy.hashCode();
result = 31 * result + optionKey.hashCode();
result = 31 * result + rankOption.hashCode();
// if a SPECIFIC, include the rank name
if (rankOption == RankOption.SPECIFIC_RANK) {
result = 31 * result + requestedRankName.hashCode();
}
return result;
}
@Override
public String toString() {
return "OptionCacheKey{" + "hierarchy=" + hierarchy.persistenceName() +
", requestedRankName='" + requestedRankName + '\'' +
", optionKey=" + optionKey.compositeKey() +
", rankOption=" + rankOption +
'}';
}
}