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 2016 ForgeRock AS.
015 */
016
017package org.forgerock.api.models;
018
019import static org.forgerock.api.util.ValidationUtil.isEmpty;
020
021import java.util.Arrays;
022import java.util.Objects;
023
024import com.fasterxml.jackson.annotation.JsonInclude;
025import com.fasterxml.jackson.annotation.JsonProperty;
026import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
027import org.forgerock.api.ApiValidationException;
028import org.forgerock.api.enums.ParameterSource;
029import org.forgerock.util.i18n.LocalizableString;
030
031/**
032 * Class that represents the Parameter type in API descriptor.
033 */
034@JsonDeserialize(builder = Parameter.Builder.class)
035@JsonInclude(JsonInclude.Include.NON_EMPTY)
036public final class Parameter {
037
038    private final String name;
039    private final String type;
040    private final String defaultValue; //Todo String?
041    private final LocalizableString description;
042    private final ParameterSource source;
043    private final Boolean required;
044    private final String[] enumValues;
045    private final String[] enumTitles;
046
047    // TODO "Other appropriate fields as described in the JSON Schema Validation spec may also be used."
048
049    /**
050     * Private Parameter constructor called by the builder.
051     *
052     * @param builder Builder that holds the values for setting the parameter properties
053     */
054    private Parameter(Builder builder) {
055        this.name = builder.name;
056        this.type = builder.type;
057        this.defaultValue = builder.defaultValue;
058        this.description = builder.description;
059        this.source = builder.source;
060        this.required = builder.required;
061        this.enumValues = builder.enumValues;
062        this.enumTitles = builder.enumTitles;
063
064        if (isEmpty(name) || isEmpty(type) || source == null) {
065            throw new ApiValidationException("name, type, and source are required");
066        }
067        if (enumTitles != null) {
068            if (enumValues == null) {
069                throw new ApiValidationException("enum[] required when enum_values[] is defined");
070            }
071            if (enumTitles.length != enumValues.length) {
072                throw new ApiValidationException("enum[] and enum_values[] must be the same length");
073            }
074        }
075    }
076
077    /**
078     * Getter of the name of the parameter.
079     *
080     * @return Parameter name
081     */
082    public String getName() {
083        return name;
084    }
085
086    /**
087     * Getter of the parameter type.
088     *
089     * @return Parameter type
090     */
091    public String getType() {
092        return type;
093    }
094
095    /**
096     * Getter of the parameter's default value.
097     *
098     * @return Parameter default value
099     */
100    public String getDefaultValue() {
101        return defaultValue;
102    }
103
104    /**
105     * Getter of the parameter description.
106     *
107     * @return Parameter description
108     */
109    public LocalizableString getDescription() {
110        return description;
111    }
112
113    /**
114     * Getter of the parameter source.
115     *
116     * @return Parameter source enum
117     */
118    public ParameterSource getSource() {
119        return source;
120    }
121
122    /**
123     * Getter of the required property.
124     *
125     * @return Required
126     */
127    public Boolean isRequired() {
128        return required;
129    }
130
131    /**
132     * Getter of required enum-values.
133     *
134     * @return Required enum-values or {@code null}
135     */
136    @JsonProperty("enum")
137    public String[] getEnumValues() {
138        return enumValues;
139    }
140
141    /**
142     * Getter of enum-titles.
143     *
144     * @return Enum-titles or {@code null}
145     */
146    @JsonProperty("options/enum_titles")
147    public String[] getEnumTitles() {
148        return enumTitles;
149    }
150
151    @Override
152    public boolean equals(Object o) {
153        if (this == o) {
154            return true;
155        }
156        if (o == null || getClass() != o.getClass()) {
157            return false;
158        }
159        Parameter parameter = (Parameter) o;
160        return required == parameter.required
161                && Objects.equals(name, parameter.name)
162                && Objects.equals(type, parameter.type)
163                && Objects.equals(defaultValue, parameter.defaultValue)
164                && Objects.equals(description, parameter.description)
165                && source == parameter.source
166                && Arrays.equals(enumValues, parameter.enumValues)
167                && Arrays.equals(enumTitles, parameter.enumTitles);
168    }
169
170    @Override
171    public int hashCode() {
172        return Objects.hash(name, type, defaultValue, description, source, required, enumValues, enumTitles);
173    }
174
175    /**
176     * New parameter builder.
177     *
178     * @return Builder
179     */
180    public static Builder parameter() {
181        return new Builder();
182    }
183
184    /**
185     * Builds a Parameter object from the data in the annotation.
186     * @param type The type to resolve {@link LocalizableString}s from.
187     * @param parameter The annotation that holds the data
188     * @return Parameter instance
189     */
190    public static Parameter fromAnnotation(Class<?> type, org.forgerock.api.annotations.Parameter parameter) {
191        return parameter()
192                .description(new LocalizableString(parameter.description(), type))
193                .defaultValue(parameter.defaultValue())
194                .enumValues(parameter.enumValues())
195                .enumTitles(parameter.enumTitles())
196                .required(parameter.required())
197                .name(parameter.name())
198                .source(parameter.source())
199                .type(parameter.type())
200                .build();
201    }
202
203    /**
204     * Builder to construct Parameter object.
205     */
206    public static final class Builder {
207
208        private String name;
209        private String type;
210        private String defaultValue;
211        private LocalizableString description;
212        private ParameterSource source;
213        private Boolean required;
214        private String[] enumValues;
215        private String[] enumTitles;
216
217        private Builder() {
218        }
219
220        /**
221         * Set the parameter name.
222         *
223         * @param name Parameter name
224         * @return Builder
225         */
226        @JsonProperty("name")
227        public Builder name(String name) {
228            this.name = name;
229            return this;
230        }
231
232        /**
233         * Sets enum-values that must match.
234         *
235         * @param enumValues Enum-values
236         * @return Builder
237         */
238        @JsonProperty("enum")
239        public Builder enumValues(String... enumValues) {
240            this.enumValues = enumValues;
241            return this;
242        }
243
244        /**
245         * Sets enum-titles that <b>must</b> be the same length as {@link #enumValues(String[])}, if provided.
246         *
247         * @param enumTitles Enum-titles
248         * @return Builder
249         */
250        @JsonProperty("options/enum_titles")
251        public Builder enumTitles(String... enumTitles) {
252            this.enumTitles = enumTitles;
253            return this;
254        }
255
256        /**
257         * Set the parameter type.
258         *
259         * @param type Parameter type
260         * @return Builder
261         */
262        @JsonProperty("type")
263        public Builder type(String type) {
264            this.type = type;
265            return this;
266        }
267
268        /**
269         * Set the parameter default value.
270         *
271         * @param defaultValue If exists, the default value
272         * @return builder
273         */
274        @JsonProperty("defaultValue")
275        public Builder defaultValue(String defaultValue) {
276            this.defaultValue = defaultValue;
277            return this;
278        }
279
280        /**
281         * Set the parameter description.
282         *
283         * @param description The description of the parameter
284         * @return builder
285         */
286        public Builder description(LocalizableString description) {
287            this.description = description;
288            return this;
289        }
290
291        /**
292         * Set the parameter description.
293         *
294         * @param description The description of the parameter
295         * @return builder
296         */
297        @JsonProperty("description")
298        public Builder description(String description) {
299            this.description = new LocalizableString(description);
300            return this;
301        }
302
303        /**
304         * Set the parameter source.
305         *
306         * @param source Where the parameter comes from. May be: PATH or ADDITIONAL
307         * @return builder
308         */
309        @JsonProperty("source")
310        public Builder source(ParameterSource source) {
311            this.source = source;
312            return this;
313        }
314
315        /**
316         * Set the required property.
317         *
318         * @param required Whether the parameter is required
319         * @return builder
320         */
321        @JsonProperty("required")
322        public Builder required(Boolean required) {
323            this.required = required;
324            return this;
325        }
326
327        /**
328         * Builds the Parameter.
329         *
330         * @return The parameter instance
331         */
332        public Parameter build() {
333            return new Parameter(this);
334        }
335    }
336
337}