View Javadoc
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 }