1 /* 2 * The contents of this file are subject to the terms of the Common Development and 3 * Distribution License (the License). You may not use this file except in compliance with the 4 * License. 5 * 6 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 7 * specific language governing permission and limitations under the License. 8 * 9 * When distributing Covered Software, include this CDDL Header Notice in each file and include 10 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 11 * Header, with the fields enclosed by brackets [] replaced by your own identifying 12 * information: "Portions copyright [year] [name of copyright owner]". 13 * 14 * Copyright 2014-2016 ForgeRock AS. 15 */ 16 17 package org.forgerock.json.resource; 18 19 import static org.forgerock.http.header.HeaderUtil.quote; 20 21 import org.forgerock.util.Reject; 22 23 /** 24 * WarningHeader implements RFC 2616 section 14.46 - Warning. 25 * 26 * It implements Advice, which allows it to be used during the routing of CREST requests 27 * such that it can be added into the response in an appropriate location. 28 * 29 * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"> 30 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html</a> 31 * @since 2.4.0 32 */ 33 public final class AdviceWarning { 34 35 /** 36 * 100 Indicates that there is data missing from the request. 37 * 38 * ForgeRock-Specific. 39 */ 40 public final static int NOT_PRESENT = 100; 41 42 /** 43 * 110 Response is stale MUST be included whenever the returned response is stale. 44 */ 45 public static final int RESPONSE_STALE = 110; 46 47 /** 48 * 111 Revalidation failed MUST be included if a cache returns a stale response because 49 * an attempt to revalidate the response failed, due to an inability to reach the server. 50 */ 51 public static final int REVALIDATION_FAILED = 111; 52 53 /** 54 * 112 Disconnected operation SHOULD be included if the cache is intentionally 55 * disconnected from the rest of the network for a period of time. 56 */ 57 public static final int DISCONNECTED_OPERATION = 112; 58 59 /** 60 * 113 Heuristic expiration MUST be included if the cache heuristically chose a 61 * freshness lifetime greater than 24 hours and the response's age is greater than 24 hours. 62 */ 63 public static final int HEURISTIC_EXPIRATION = 113; 64 65 /** 66 * 199 Miscellaneous warning The warning text MAY include arbitrary information to be 67 * presented to a human user, or logged. A system receiving this warning MUST NOT take 68 * any automated action, besides presenting the warning to the user. 69 */ 70 public static final int MISCELLANEOUS_WARNING = 199; 71 72 /** 73 * 214 Transformation applied MUST be added by an intermediate cache or proxy if it applies 74 * any transformation changing the content-coding (as specified in the Content-Encoding header) 75 * or media-type (as specified in the Content-Type header) of the response, or the entity-body 76 * of the response, unless this Warning code already appears in the response. 77 */ 78 public static final int TRANFORMATION_APPLIED = 214; 79 80 /** 81 * 299 Miscellaneous persistent warning The warning text MAY include arbitrary information to 82 * be presented to a human user, or logged. A system receiving this warning MUST NOT take any automated action. 83 */ 84 public static final int MISCELLANEOUS_PERSISTENT_WARNING = 299; 85 86 private final int warningCode; 87 private final String warningAgent; 88 private final String warningText; 89 90 private AdviceWarning(Builder builder) { 91 Reject.ifNull(builder.warningAgent, builder.warningText); 92 warningCode = builder.warningCode; 93 warningAgent = builder.warningAgent; 94 warningText = builder.warningText; 95 } 96 97 @Override 98 public String toString() { 99 return String.valueOf(warningCode) + " " + warningAgent + " " + quote(warningText); 100 } 101 102 /** 103 * Convenience method to quickly generate frequently-used error type: 100. 104 * 105 * @param agentName Name of the component responsible for issuing the warning. 106 * @param missingKey Name of the missing key which must be included. 107 * @return a newly constructed AdviceWarning indicating the expected key was not found in the request. 108 */ 109 public static AdviceWarning getNotPresent(String agentName, String missingKey) { 110 return AdviceWarning.newBuilder() 111 .withWarningAgent(agentName) 112 .withWarningCode(NOT_PRESENT) 113 .withWarningText(missingKey + " should be included in the request.") 114 .build(); 115 } 116 117 /** 118 * Generate a warning using the builder provided. 119 * 120 * @param agentName the agent name 121 * @param fmt The format, which may include embedded %s, etc. 122 * @param args Zero or more args, passed into String.format to generate the warning text 123 * @return a newly built WarningHeader object 124 */ 125 public static AdviceWarning newAdviceWarning(String agentName, String fmt, Object... args) { 126 return AdviceWarning 127 .newBuilder() 128 .withWarningAgent(agentName) 129 .withWarningCode(NOT_PRESENT) 130 .withWarningText(String.format(fmt, args)) 131 .build(); 132 } 133 134 private static Builder newBuilder() { 135 return new Builder(); 136 } 137 138 /** 139 * Accessed via {@link AdviceWarning#newBuilder()}. 140 */ 141 private static final class Builder { 142 143 private int warningCode; 144 private String warningAgent; 145 private String warningText; 146 147 /** 148 * Package private default CTOR to prevent direct instantiation by other than us. 149 */ 150 private Builder() { 151 } 152 153 /** 154 * A three-digit code which can be linked back to the cause of the Warning. 155 * 156 * @param warningCode a three-digit integer. 157 * @return this builder. 158 */ 159 private Builder withWarningCode(int warningCode) { 160 Reject.ifTrue(warningCode < 0); 161 Reject.ifTrue(String.valueOf(warningCode).length() != 3); 162 this.warningCode = warningCode; 163 return this; 164 } 165 166 /** 167 * An identifier, used for debugging so that the receiving agent can 168 * determine from where this Warning originated. 169 * 170 * @param warningAgent a String identifier. 171 * @return this builder. 172 */ 173 private Builder withWarningAgent(String warningAgent) { 174 Reject.ifNull(warningAgent); 175 Reject.ifTrue(warningAgent.isEmpty()); 176 this.warningAgent = warningAgent; 177 return this; 178 } 179 180 /** 181 * A human-readable description of the Warning. 182 * 183 * @param warningText a String description 184 * @return this builder. 185 */ 186 private Builder withWarningText(String warningText) { 187 Reject.ifNull(warningText); 188 Reject.ifTrue(warningText.isEmpty()); 189 this.warningText = warningText; 190 return this; 191 } 192 193 /** 194 * Builds and returns a valid and usable {@code WarningHeader} from this 195 * builder. 196 * 197 * @return The built {@code WarningHeader}. 198 */ 199 private AdviceWarning build() { 200 return new AdviceWarning(this); 201 } 202 } 203 }