001/* 002* The contents of this file are subject to the terms of the Common Development and 003* Distribution License (the License). You may not use this file except in compliance with the 004* License. 005* 006* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007* specific language governing permission and limitations under the License. 008* 009* When distributing Covered Software, include this CDDL Header Notice in each file and include 010* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011* Header, with the fields enclosed by brackets [] replaced by your own identifying 012* information: "Portions copyright [year] [name of copyright owner]". 013* 014* Copyright 2014 ForgeRock AS. 015*/ 016 017package org.forgerock.json.resource; 018 019import org.forgerock.util.Reject; 020 021/** 022 * WarningHeader implements RFC 2616 section 14.46 - Warning. 023 * 024 * It implements Advice, which allows it to be used during the routing of CREST requests 025 * such that it can be added into the response in an appropriate location. 026 * 027 * @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"> 028 * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html</a> 029 * @since 2.4.0 030 */ 031public final class AdviceWarning { 032 033 /** 034 * 100 Indicates that there is data missing from the request. 035 * 036 * ForgeRock-Specific. 037 */ 038 public final static int NOT_PRESENT = 100; 039 040 /** 041 * 110 Response is stale MUST be included whenever the returned response is stale. 042 */ 043 public static final int RESPONSE_STALE = 110; 044 045 /** 046 * 111 Revalidation failed MUST be included if a cache returns a stale response because 047 * an attempt to revalidate the response failed, due to an inability to reach the server. 048 */ 049 public static final int REVALIDATION_FAILED = 111; 050 051 /** 052 * 112 Disconnected operation SHOULD be included if the cache is intentionally 053 * disconnected from the rest of the network for a period of time. 054 */ 055 public static final int DISCONNECTED_OPERATION = 112; 056 057 /** 058 * 113 Heuristic expiration MUST be included if the cache heuristically chose a 059 * freshness lifetime greater than 24 hours and the response's age is greater than 24 hours. 060 */ 061 public static final int HEURISTIC_EXPIRATION = 113; 062 063 /** 064 * 199 Miscellaneous warning The warning text MAY include arbitrary information to be 065 * presented to a human user, or logged. A system receiving this warning MUST NOT take 066 * any automated action, besides presenting the warning to the user. 067 */ 068 public static final int MISCELLANEOUS_WARNING = 199; 069 070 /** 071 * 214 Transformation applied MUST be added by an intermediate cache or proxy if it applies 072 * any transformation changing the content-coding (as specified in the Content-Encoding header) 073 * or media-type (as specified in the Content-Type header) of the response, or the entity-body 074 * of the response, unless this Warning code already appears in the response. 075 */ 076 public static final int TRANFORMATION_APPLIED = 214; 077 078 /** 079 * 299 Miscellaneous persistent warning The warning text MAY include arbitrary information to 080 * be presented to a human user, or logged. A system receiving this warning MUST NOT take any automated action. 081 */ 082 public static final int MISCELLANEOUS_PERSISTENT_WARNING = 299; 083 084 private final int warningCode; 085 private final String warningAgent; 086 private final String warningText; 087 088 private AdviceWarning(Builder builder) { 089 Reject.ifNull(builder.warningAgent, builder.warningText); 090 warningCode = builder.warningCode; 091 warningAgent = builder.warningAgent; 092 warningText = builder.warningText; 093 } 094 095 @Override 096 public String toString() { 097 return String.valueOf(warningCode) + " " + warningAgent + " " + warningText; 098 } 099 100 /** 101 * Convenience method to quickly generate frequently-used error type: 100. 102 * 103 * @param agentName Name of the component responsible for issuing the warning. 104 * @param missingKey Name of the missing key which must be included. 105 * @return a newly constructed AdviceWarning indicating the expected key was not found in the request. 106 */ 107 public static AdviceWarning getNotPresent(String agentName, String missingKey) { 108 return AdviceWarning.newBuilder() 109 .withWarningAgent(agentName) 110 .withWarningCode(NOT_PRESENT) 111 .withWarningText(missingKey + " should be included in the request.") 112 .build(); 113 } 114 115 /** 116 * Generate a warning using the builder provided. 117 * 118 * @param agentName the agent name 119 * @param fmt The format, which may include embedded %s, etc. 120 * @param args Zero or more args, passed into String.format to generate the warning text 121 * @return a newly built WarningHeader object 122 */ 123 public static AdviceWarning newAdviceWarning(String agentName, String fmt, Object... args) { 124 return AdviceWarning 125 .newBuilder() 126 .withWarningAgent(agentName) 127 .withWarningCode(NOT_PRESENT) 128 .withWarningText(String.format(fmt, args)) 129 .build(); 130 } 131 132 private static Builder newBuilder() { 133 return new Builder(); 134 } 135 136 /** 137 * Accessed via {@link AdviceWarning#newBuilder()}. 138 */ 139 private static final class Builder { 140 141 private int warningCode; 142 private String warningAgent; 143 private String warningText; 144 145 /** 146 * Package private default CTOR to prevent direct instantiation by other than us. 147 */ 148 private Builder() { 149 } 150 151 /** 152 * A three-digit code which can be linked back to the cause of the Warning. 153 * 154 * @param warningCode a three-digit integer. 155 * @return this builder. 156 */ 157 private Builder withWarningCode(int warningCode) { 158 Reject.ifTrue(warningCode < 0); 159 Reject.ifTrue(String.valueOf(warningCode).length() != 3); 160 this.warningCode = warningCode; 161 return this; 162 } 163 164 /** 165 * An identifier, used for debugging so that the receiving agent can 166 * determine from where this Warning originated. 167 * 168 * @param warningAgent a String identifier. 169 * @return this builder. 170 */ 171 private Builder withWarningAgent(String warningAgent) { 172 Reject.ifNull(warningAgent); 173 Reject.ifTrue(warningAgent.isEmpty()); 174 this.warningAgent = warningAgent; 175 return this; 176 } 177 178 /** 179 * A human-readable description of the Warning. 180 * 181 * @param warningText a String description 182 * @return this builder. 183 */ 184 private Builder withWarningText(String warningText) { 185 Reject.ifNull(warningText); 186 Reject.ifTrue(warningText.isEmpty()); 187 this.warningText = warningText; 188 return this; 189 } 190 191 /** 192 * Builds and returns a valid and usable {@code WarningHeader} from this 193 * builder. 194 * 195 * @return The built {@code WarningHeader}. 196 */ 197 private AdviceWarning build() { 198 return new AdviceWarning(this); 199 } 200 } 201}