| // Copyright 2010 Google Inc. |
| // |
| // 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 com.google.enterprise.adaptor.secmgr.modules; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Maps; |
| import com.google.common.collect.Ordering; |
| import com.google.enterprise.adaptor.secmgr.common.AuthzStatus; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import javax.annotation.concurrent.Immutable; |
| import javax.annotation.concurrent.NotThreadSafe; |
| |
| /** |
| * Instances of this class are the return value from an authorization process. |
| * At the moment this is just some fancy constructors that create a delegated |
| * map. |
| */ |
| @Immutable |
| public final class AuthzResult implements Map<String, AuthzStatus> { |
| private final ImmutableMap<String, AuthzStatus> statusMap; |
| private final ImmutableSet<String> cacheResults; |
| |
| private AuthzResult(ImmutableMap<String, AuthzStatus> statusMap, |
| ImmutableSet<String> determinedByCache) { |
| this.statusMap = statusMap; |
| this.cacheResults = determinedByCache; |
| } |
| |
| /** |
| * Get an {@link AuthzResult} builder that has a minimum set of resources. |
| * This builder generates an AuthzResult instance that's guaranteed to have a |
| * status for every resource in {@code resources}; those that aren't |
| * explicitly set in the builder will map to {@link |
| * AuthzStatus#INDETERMINATE}. |
| * |
| * @param resources The minimum set of resources to use for the returned |
| * builder. |
| * @return An {@link AuthzResult} builder. |
| */ |
| public static Builder builder(Iterable<String> resources) { |
| Preconditions.checkNotNull(resources); |
| return new Builder(resources); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} builder that expands on a previous result. |
| * |
| * @param map The previous result. |
| * @return An {@link AuthzResult} builder. |
| */ |
| public static Builder builder(Map<String, AuthzStatus> map) { |
| Preconditions.checkNotNull(map); |
| return new Builder(map); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} builder that has a no minimum set of resources; |
| * this is equivalent to passing an empty set of resources as an argument. |
| * |
| * @return An {@link AuthzResult} builder. |
| */ |
| public static Builder builder() { |
| ImmutableList<String> resources = ImmutableList.of(); |
| return new Builder(resources); |
| } |
| |
| /** |
| * Find out if a resource's determination (PERMIT or DENY) came from |
| * UserCacheConnector. |
| * |
| * @return True if resource's determiantion came from UserCacheConnector. |
| */ |
| public boolean wasDeterminedByCache(String resource) { |
| return cacheResults.contains(resource); |
| } |
| |
| /** |
| * A builder class for AuthzResult instances. |
| */ |
| @NotThreadSafe |
| public static final class Builder { |
| |
| private final Map<String, AuthzStatus> map; |
| private final ImmutableSet.Builder<String> determinedByCache; // PERMIT or DENY. |
| |
| private Builder(Iterable<String> resources) { |
| map = Maps.newHashMap(); |
| for (String resource : resources) { |
| map.put(resource, AuthzStatus.INDETERMINATE); |
| } |
| determinedByCache = ImmutableSet.builder(); |
| } |
| |
| private Builder(Map<String, AuthzStatus> map) { |
| this.map = Maps.newHashMap(map); |
| determinedByCache = ImmutableSet.builder(); |
| } |
| |
| /** |
| * Add an entry to the builder. |
| * |
| * @param resource The resource for the new entry. |
| * @param status The status for the new entry. |
| * @return The builder, for convenience. |
| */ |
| public Builder put(String resource, AuthzStatus status) { |
| Preconditions.checkNotNull(resource); |
| Preconditions.checkNotNull(status); |
| map.put(resource, status); |
| return this; |
| } |
| |
| /** |
| * Add PERMIT or DENY from cache to the builder. |
| * |
| * @param resource The resource for the new entry. |
| * @param status The status for the new entry. |
| * @return The builder, for convenience. |
| */ |
| public Builder putStatusFromCache(String resource, AuthzStatus status) { |
| Preconditions.checkNotNull(resource); |
| Preconditions.checkNotNull(status); |
| map.put(resource, status); |
| if (AuthzStatus.INDETERMINATE != status) { |
| determinedByCache.add(resource); |
| } |
| return this; |
| } |
| |
| /** |
| * Add an entry to the builder. |
| * |
| * @param entry The entry to add. |
| * @return The builder, for convenience. |
| */ |
| public Builder add(Map.Entry<String, AuthzStatus> entry) { |
| Preconditions.checkNotNull(entry); |
| return put(entry.getKey(), entry.getValue()); |
| } |
| |
| /** |
| * Add a map of entries to the builder. |
| * |
| * @param map The map to add. |
| * @return The builder, for convenience. |
| */ |
| public Builder addAll(Map<String, AuthzStatus> map) { |
| Preconditions.checkNotNull(map); |
| for (Map.Entry<String, AuthzStatus> entry : map.entrySet()) { |
| put(entry.getKey(), entry.getValue()); |
| } |
| return this; |
| } |
| |
| /** |
| * @return The {@link AuthzResult} instance that's been constructed by this |
| * builder. Calling this method more than once on the same builder |
| * instance is not guaranteed to work. |
| */ |
| public AuthzResult build() { |
| return new AuthzResult(ImmutableMap.copyOf(map), determinedByCache.build()); |
| } |
| } |
| |
| /** |
| * Make an {@link AuthzResult} in which all of the resources have |
| * indeterminate status. |
| * |
| * @param resources The resources in the result. |
| * @return An AuthzResult instance. |
| */ |
| public static AuthzResult makeIndeterminate(Iterable<String> resources) { |
| return builder(resources).build(); |
| } |
| |
| /** |
| * @return An empty {@link AuthzResult}. |
| */ |
| public static AuthzResult of() { |
| return builder().build(); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} with a single entry. |
| * |
| * @param r1 The single resource. |
| * @param s1 The status for that resource. |
| * @return The result instance. |
| */ |
| public static AuthzResult of(String r1, AuthzStatus s1) { |
| return AuthzResult.builder() |
| .put(r1, s1) |
| .build(); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} with two entries. |
| * |
| * @param r1 The first resource. |
| * @param s1 The status for the first resource. |
| * @param r2 The second resource. |
| * @param s2 The status for the second resource. |
| * @return The result instance. |
| */ |
| public static AuthzResult of(String r1, AuthzStatus s1, String r2, AuthzStatus s2) { |
| return AuthzResult.builder() |
| .put(r1, s1) |
| .put(r2, s2) |
| .build(); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} with three entries. |
| * |
| * @param r1 The first resource. |
| * @param s1 The status for the first resource. |
| * @param r2 The second resource. |
| * @param s2 The status for the second resource. |
| * @param r3 The third resource. |
| * @param s3 The status for the third resource. |
| * @return The result instance. |
| */ |
| public static AuthzResult of(String r1, AuthzStatus s1, String r2, AuthzStatus s2, |
| String r3, AuthzStatus s3) { |
| return AuthzResult.builder() |
| .put(r1, s1) |
| .put(r2, s2) |
| .put(r3, s3) |
| .build(); |
| } |
| |
| /** |
| * Get an {@link AuthzResult} with four entries. |
| * |
| * @param r1 The first resource. |
| * @param s1 The status for the first resource. |
| * @param r2 The second resource. |
| * @param s2 The status for the second resource. |
| * @param r3 The third resource. |
| * @param s3 The status for the third resource. |
| * @param r4 The fourth resource. |
| * @param s4 The status for the fourth resource. |
| * @return The result instance. |
| */ |
| public static AuthzResult of(String r1, AuthzStatus s1, String r2, AuthzStatus s2, |
| String r3, AuthzStatus s3, String r4, AuthzStatus s4) { |
| return AuthzResult.builder() |
| .put(r1, s1) |
| .put(r2, s2) |
| .put(r3, s3) |
| .put(r4, s4) |
| .build(); |
| } |
| |
| @Override |
| public Set<String> keySet() { |
| return statusMap.keySet(); |
| } |
| |
| @Override |
| public Set<Map.Entry<String, AuthzStatus>> entrySet() { |
| return statusMap.entrySet(); |
| } |
| |
| @Override |
| public int size() { |
| return statusMap.size(); |
| } |
| |
| @Override |
| public AuthzStatus get(Object resource) { |
| return statusMap.get(resource); |
| } |
| |
| @Override |
| public boolean containsKey(Object key) { |
| return statusMap.containsKey(key); |
| } |
| |
| @Override |
| public boolean containsValue(Object value) { |
| return statusMap.containsValue(value); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return statusMap.isEmpty(); |
| } |
| |
| @Override |
| public Collection<AuthzStatus> values() { |
| return statusMap.values(); |
| } |
| |
| @Override |
| public boolean equals(Object object) { |
| return statusMap.equals(object); |
| } |
| |
| @Override |
| public int hashCode() { |
| return statusMap.hashCode(); |
| } |
| |
| @Override |
| public void clear() { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public AuthzStatus put(String key, AuthzStatus value) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public void putAll(Map<? extends String, ? extends AuthzStatus> m) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public AuthzStatus remove(Object key) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| @Override |
| public String toString() { |
| StringBuilder builder = new StringBuilder(); |
| boolean firstElt = true; |
| builder.append("{"); |
| for (String resource : Ordering.natural().sortedCopy(statusMap.keySet())) { |
| if (!firstElt) { |
| builder.append(','); |
| } else { |
| firstElt = false; |
| } |
| builder.append("\n \""); |
| builder.append(resource); |
| builder.append("\", "); |
| builder.append(statusMap.get(resource)); |
| } |
| builder.append("\n}"); |
| return builder.toString(); |
| } |
| } |