001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.console.views; 018 019import java.util.*; 020 021import org.apache.juneau.commons.bean.*; 022 023/** 024 * The response shape of an {@code aggregate}-mode bulk action ({@link RowAction.BulkMode#AGGREGATE}) — 025 * one outcome per id submitted in the matching {@link BulkRequest}. 026 * 027 * <h5 class='section'>Own, independently-versioned contract</h5> 028 * <p> 029 * {@link #CONTRACT_VERSION} is this type's own wire contract, never aliased to {@code VIEW}, {@code ACTION_RESULT}, 030 * or {@link BulkMutateDef#CONTRACT_VERSION} — each of those versions what it defines (a view's shape, a 031 * single-row action's outcome, a bulk-mutate action list) and this one versions only this response shape. 032 * 033 * <h5 class='section'>Example:</h5> 034 * <p class='bjava'> 035 * <ja>@RestPost</ja>(path=<js>"/changes/abort"</js>) 036 * <jk>public</jk> BulkResult abortChanges(<ja>@Content</ja> BulkRequest <jv>request</jv>) { 037 * BulkResult.Builder <jv>result</jv> = BulkResult.<jsm>create</jsm>(); 038 * <jk>for</jk> (String <jv>id</jv> : <jv>request</jv>.ids) { 039 * Change <jv>change</jv> = <jv>changeStore</jv>.find(<jv>id</jv>); 040 * <jk>if</jk> (<jv>change</jv> == <jk>null</jk>) { 041 * <jv>result</jv>.notFound(<jv>id</jv>); 042 * } <jk>else if</jk> (!<js>"PENDING"</js>.equals(<jv>change</jv>.state)) { 043 * <jv>result</jv>.failed(<jk>new</jk> BulkResult.Failure(<jv>id</jv>, <js>"Change is already merged."</js>)); 044 * } <jk>else</jk> { 045 * <jv>changeStore</jv>.abort(<jv>id</jv>); 046 * <jv>result</jv>.succeeded(<jv>id</jv>); 047 * } 048 * } 049 * <jk>return</jk> <jv>result</jv>.build(); 050 * } 051 * </p> 052 * 053 * @since 10.0.0 054 */ 055@BeanType(properties="contractVersion,succeeded,notFound,failed") 056public final class BulkResult { 057 058 /** This type's own wire contract version. */ 059 public static final String CONTRACT_VERSION = "1"; 060 061 /** 062 * One failed-outcome entry: the id that was submitted, and why it failed. 063 * 064 * @param id The submitted id. 065 * @param message Why it failed. 066 * @since 10.0.0 067 */ 068 public record Failure(String id, String message) {} 069 070 /** The frozen contract-version discriminator (always {@value #CONTRACT_VERSION}). */ 071 public final String contractVersion; 072 073 /** The ids that succeeded. */ 074 public final List<String> succeeded; 075 076 /** The ids that were submitted but no longer exist. */ 077 public final List<String> notFound; 078 079 /** The ids that failed, with a reason each. */ 080 public final List<Failure> failed; 081 082 private BulkResult(Builder b) { 083 contractVersion = CONTRACT_VERSION; 084 succeeded = List.copyOf(b.succeeded); 085 notFound = List.copyOf(b.notFound); 086 failed = List.copyOf(b.failed); 087 } 088 089 /** 090 * Starts a new {@link Builder}. 091 * 092 * @return A new, empty builder. 093 */ 094 public static Builder create() { 095 return new Builder(); 096 } 097 098 /** 099 * This result's contract version. 100 * 101 * @return {@link #CONTRACT_VERSION}. 102 */ 103 public String contractVersion() { 104 return contractVersion; 105 } 106 107 /** 108 * The ids that succeeded. 109 * 110 * @return An immutable list. Never <jk>null</jk>. 111 */ 112 public List<String> succeeded() { 113 return succeeded; 114 } 115 116 /** 117 * The ids that were submitted but no longer exist (e.g. deleted between selection and submit). 118 * 119 * @return An immutable list. Never <jk>null</jk>. 120 */ 121 public List<String> notFound() { 122 return notFound; 123 } 124 125 /** 126 * The ids that failed, with a reason each. 127 * 128 * @return An immutable list. Never <jk>null</jk>. 129 */ 130 public List<Failure> failed() { 131 return failed; 132 } 133 134 /** 135 * A mutable builder for {@link BulkResult}. 136 * 137 * @since 10.0.0 138 */ 139 public static final class Builder { 140 141 private final List<String> succeeded = new ArrayList<>(); 142 private final List<String> notFound = new ArrayList<>(); 143 private final List<Failure> failed = new ArrayList<>(); 144 145 private Builder() {} 146 147 /** 148 * Appends ids to the succeeded list. 149 * 150 * @param ids The ids. May be called more than once; each call appends. 151 * @return This builder. 152 */ 153 public Builder succeeded(String...ids) { 154 succeeded.addAll(Arrays.asList(ids)); 155 return this; 156 } 157 158 /** 159 * Appends ids to the not-found list. 160 * 161 * @param ids The ids. May be called more than once; each call appends. 162 * @return This builder. 163 */ 164 public Builder notFound(String...ids) { 165 notFound.addAll(Arrays.asList(ids)); 166 return this; 167 } 168 169 /** 170 * Appends failures to the failed list. 171 * 172 * @param failures The failures. May be called more than once; each call appends. 173 * @return This builder. 174 */ 175 public Builder failed(Failure...failures) { 176 failed.addAll(Arrays.asList(failures)); 177 return this; 178 } 179 180 /** 181 * Builds the immutable {@link BulkResult}. 182 * 183 * @return A new {@link BulkResult}. 184 */ 185 public BulkResult build() { 186 return new BulkResult(this); 187 } 188 } 189}