Line data Source code
1 : // Copyright (C) 2018 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.quota; 16 : 17 : import static com.google.common.collect.ImmutableList.toImmutableList; 18 : 19 : import com.google.auto.value.AutoValue; 20 : import com.google.common.base.Strings; 21 : import com.google.common.collect.ImmutableList; 22 : import com.google.common.collect.Streams; 23 : import java.util.Collection; 24 : import java.util.Optional; 25 : import java.util.OptionalLong; 26 : import java.util.stream.Collectors; 27 : 28 : @AutoValue 29 1 : public abstract class QuotaResponse { 30 1 : public enum Status { 31 : /** The quota requests succeeded. */ 32 1 : OK, 33 : 34 : /** 35 : * The quota succeeded, but was a no-op because the plugin does not enforce this quota group 36 : * (equivalent to OK, but relevant for debugging). 37 : */ 38 1 : NO_OP, 39 : 40 : /** 41 : * The requested quota could not be allocated. This status code is not used to indicate 42 : * processing failures as these are propagated as {@code RuntimeException}s. 43 : */ 44 1 : ERROR; 45 : 46 : public boolean isOk() { 47 1 : return this == OK; 48 : } 49 : 50 : public boolean isError() { 51 1 : return this == ERROR; 52 : } 53 : } 54 : 55 : public static QuotaResponse ok() { 56 1 : return new AutoValue_QuotaResponse.Builder().status(Status.OK).build(); 57 : } 58 : 59 : public static QuotaResponse ok(long tokens) { 60 1 : return new AutoValue_QuotaResponse.Builder().status(Status.OK).availableTokens(tokens).build(); 61 : } 62 : 63 : public static QuotaResponse noOp() { 64 1 : return new AutoValue_QuotaResponse.Builder().status(Status.NO_OP).build(); 65 : } 66 : 67 : public static QuotaResponse error(String message) { 68 1 : return new AutoValue_QuotaResponse.Builder().status(Status.ERROR).message(message).build(); 69 : } 70 : 71 : public abstract Status status(); 72 : 73 : public abstract Optional<Long> availableTokens(); 74 : 75 : public abstract Optional<String> message(); 76 : 77 : @AutoValue.Builder 78 1 : public abstract static class Builder { 79 : public abstract QuotaResponse.Builder status(Status status); 80 : 81 : public abstract QuotaResponse.Builder availableTokens(Long tokens); 82 : 83 : public abstract QuotaResponse.Builder message(String message); 84 : 85 : public abstract QuotaResponse build(); 86 : } 87 : 88 : @AutoValue 89 104 : public abstract static class Aggregated { 90 : public static Aggregated create(Collection<QuotaResponse> responses) { 91 104 : return new AutoValue_QuotaResponse_Aggregated(ImmutableList.copyOf(responses)); 92 : } 93 : 94 : protected abstract ImmutableList<QuotaResponse> responses(); 95 : 96 : public boolean hasError() { 97 2 : return responses().stream().anyMatch(r -> r.status().isError()); 98 : } 99 : 100 : public ImmutableList<QuotaResponse> all() { 101 0 : return responses(); 102 : } 103 : 104 : public ImmutableList<QuotaResponse> ok() { 105 0 : return responses().stream().filter(r -> r.status().isOk()).collect(toImmutableList()); 106 : } 107 : 108 : public OptionalLong availableTokens() { 109 97 : return responses().stream() 110 97 : .filter(r -> r.status().isOk() && r.availableTokens().isPresent()) 111 97 : .mapToLong(r -> r.availableTokens().get()) 112 97 : .min(); 113 : } 114 : 115 : public ImmutableList<QuotaResponse> error() { 116 104 : return responses().stream().filter(r -> r.status().isError()).collect(toImmutableList()); 117 : } 118 : 119 : public String errorMessage() { 120 104 : return error().stream() 121 104 : .map(QuotaResponse::message) 122 104 : .flatMap(Streams::stream) 123 104 : .collect(Collectors.joining(", ")); 124 : } 125 : 126 : public void throwOnError() throws QuotaException { 127 104 : String errorMessage = errorMessage(); 128 104 : if (!Strings.isNullOrEmpty(errorMessage)) { 129 1 : throw new QuotaException(errorMessage); 130 : } 131 104 : } 132 : } 133 : }