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 2016-2017 ForgeRock AS.
15   */
16  
17  package org.forgerock.api.models;
18  
19  import static org.forgerock.api.models.ApiError.apiError;
20  import static org.forgerock.api.models.Reference.reference;
21  import static org.forgerock.api.util.ValidationUtil.isEmpty;
22  
23  import java.util.ArrayList;
24  import java.util.Arrays;
25  import java.util.List;
26  import java.util.Objects;
27  
28  import com.fasterxml.jackson.annotation.JsonInclude;
29  import com.fasterxml.jackson.annotation.JsonProperty;
30  import org.forgerock.api.enums.Stability;
31  import org.forgerock.util.i18n.LocalizableString;
32  import org.slf4j.Logger;
33  import org.slf4j.LoggerFactory;
34  
35  /**
36   * Class that represents the Operation type in API descriptor.
37   */
38  @JsonInclude(JsonInclude.Include.NON_NULL)
39  public abstract class Operation {
40  
41      private static final Logger logger = LoggerFactory.getLogger(Operation.class);
42  
43      private final LocalizableString description;
44      private final String[] supportedLocales;
45      @JsonProperty("errors")
46      private final ApiError[] apiErrors;
47      private final Parameter[] parameters;
48      private final Stability stability;
49  
50      /**
51       * Protected constructor of the Operation.
52       *
53       * @param builder Operation Builder
54       */
55      protected Operation(Builder builder) {
56          this.description = builder.description;
57          this.supportedLocales = builder.supportedLocales;
58          this.stability = builder.stability;
59  
60          final List<ApiError> apiErrors = builder.apiErrors;
61          this.apiErrors = apiErrors.toArray(new ApiError[apiErrors.size()]);
62  
63          final List<Parameter> parameters = builder.parameters;
64          this.parameters = parameters.toArray(new Parameter[parameters.size()]);
65      }
66  
67      /**
68       * Getter of the description.
69       *
70       * @return Description
71       */
72      public LocalizableString getDescription() {
73          return description;
74      }
75  
76      /**
77       * Getter of the supported locales array.
78       *
79       * @return Supported locales
80       */
81      public String[] getSupportedLocales() {
82          return supportedLocales;
83      }
84  
85      /**
86       * Getter of the error array.
87       *
88       * @return ApiError array
89       */
90      public ApiError[] getApiErrors() {
91          return apiErrors.length == 0 ? null : apiErrors;
92      }
93  
94      /**
95       * Getter of the parameters array.
96       *
97       * @return Parameters
98       */
99      public Parameter[] getParameters() {
100         return parameters.length == 0 ? null : parameters;
101     }
102 
103     /**
104      * Getter of Operation stability.
105      *
106      * @return Stability or {@code null} which suggests {@link Stability#STABLE} (default).
107      */
108     public Stability getStability() {
109         return stability;
110     }
111 
112     @Override
113     public boolean equals(Object o) {
114         if (this == o) {
115             return true;
116         }
117         if (o == null || getClass() != o.getClass()) {
118             return false;
119         }
120         Operation operation = (Operation) o;
121         return Objects.equals(description, operation.description)
122                 && Arrays.equals(supportedLocales, operation.supportedLocales)
123                 && Arrays.equals(apiErrors, operation.apiErrors)
124                 && Arrays.equals(parameters, operation.parameters)
125                 && stability == operation.stability;
126     }
127 
128     @Override
129     public int hashCode() {
130         return Objects.hash(description, supportedLocales, apiErrors, parameters, stability);
131     }
132 
133     /**
134      * Allocates the operation by operation type to the given Resource Builder
135      * by calling the corresonding method by type.
136      *
137      * @param resourceBuilder - Resource Builder to add the operation
138      */
139     protected abstract void allocateToResource(Resource.Builder resourceBuilder);
140 
141     /**
142      * Builder to help construct the Operation.
143      */
144     public abstract static class Builder<T extends Builder<T>> {
145 
146         private LocalizableString description;
147         private String[] supportedLocales;
148         private final List<ApiError> apiErrors;
149         private final List<Parameter> parameters;
150         private Stability stability;
151 
152         /**
153          * Creates a new Builder.
154          */
155         protected Builder() {
156             apiErrors = new ArrayList<>();
157             parameters = new ArrayList<>();
158         }
159 
160         /**
161          * Abstract method that returns the instantiated Builder itself.
162          *
163          * @return Builder
164          */
165         protected abstract T self();
166 
167         /**
168          * Set the description.
169          *
170          * @param description A description of the endpoint
171          * @return Builder
172          */
173         public T description(LocalizableString description) {
174             this.description = description;
175             return self();
176         }
177 
178         /**
179          * Set the description.
180          *
181          * @param description A description of the endpoint
182          * @return Builder
183          */
184         @JsonProperty("description")
185         public T description(String description) {
186             this.description = new LocalizableString(description);
187             return self();
188         }
189 
190         /**
191          * Set the supported locale.
192          *
193          * @param supportedlocales Locales codes supported by the operation
194          * @return Builder
195          */
196         @JsonProperty("supportedLocales")
197         public T supportedLocales(String... supportedlocales) {
198             this.supportedLocales = supportedlocales;
199             return self();
200         }
201 
202         /**
203          * Set multiple supported errors.
204          *
205          * @param apiErrors What errors may be returned by this operation
206          * @return Builder
207          */
208         @JsonProperty("errors")
209         public T errors(List<ApiError> apiErrors) {
210             this.apiErrors.addAll(apiErrors);
211             return self();
212         }
213 
214         /**
215          * Sets a single supported error.
216          *
217          * @param apiError An error that may be returned by this operation
218          * @return Builder
219          */
220         public T error(ApiError apiError) {
221             this.apiErrors.add(apiError);
222             return self();
223         }
224 
225         /**
226          * Set multiple supported parameters.
227          *
228          * @param parameters Extra parameters supported by the operation
229          * @return Builder
230          */
231         @JsonProperty("parameters")
232         public T parameters(List<Parameter> parameters) {
233             this.parameters.addAll(parameters);
234             return self();
235         }
236 
237         /**
238          * Sets a single supported parameters.
239          *
240          * @param parameter Extra parameter supported by the operation
241          * @return Builder
242          */
243         public T parameter(Parameter parameter) {
244             this.parameters.add(parameter);
245             return self();
246         }
247 
248         /**
249          * Sets stability of Operation.
250          *
251          * @param stability Stability
252          * @return Builder
253          */
254         @JsonProperty("stability")
255         public T stability(Stability stability) {
256             this.stability = stability;
257             return self();
258         }
259 
260         /**
261          * Set all properties in the Builder using the data in the annotation.
262          * @param operation The annotation that holds the data
263          * @param descriptor The root descriptor
264          * @param relativeType The type relative to which schema resources should be resolved.
265          * @return Builder
266          */
267         public T detailsFromAnnotation(org.forgerock.api.annotations.Operation operation,
268                 ApiDescription descriptor, Class<?> relativeType) {
269             for (String ref : operation.errorRefs()) {
270                 if (isEmpty(ref)) {
271                     logger.debug("Empty errorRefs array-element ignored on: " + relativeType.getCanonicalName());
272                 } else {
273                     error(apiError().reference(reference().value(ref).build()).build());
274                 }
275             }
276             for (org.forgerock.api.annotations.ApiError apiApiError : operation.errors()) {
277                 error(ApiError.fromAnnotation(apiApiError, descriptor, relativeType));
278             }
279             for (org.forgerock.api.annotations.Parameter parameter : operation.parameters()) {
280                 parameter(Parameter.fromAnnotation(relativeType, parameter));
281             }
282             return description(new LocalizableString(operation.description(), relativeType))
283                     .supportedLocales(operation.locales())
284                     .stability(operation.stability());
285         }
286     }
287 
288 }