001/*
002 * Copyright (c) 2010-2025 Mark Allen, Norbert Bartels.
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a copy
005 * of this software and associated documentation files (the "Software"), to deal
006 * in the Software without restriction, including without limitation the rights
007 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008 * copies of the Software, and to permit persons to whom the Software is
009 * furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
020 * THE SOFTWARE.
021 */
022package com.restfb;
023
024import static com.restfb.util.StringUtils.isBlank;
025import static com.restfb.util.StringUtils.trimToEmpty;
026import static java.lang.String.format;
027
028import java.util.Locale;
029import java.util.Objects;
030import java.util.Optional;
031
032import com.restfb.exception.FacebookJsonMappingException;
033
034/**
035 * Representation of a Facebook API request parameter.
036 * 
037 * @author <a href="http://restfb.com">Mark Allen</a>
038 */
039public final class Parameter {
040  /**
041   * Parameter name.
042   */
043  public final String name;
044
045  /**
046   * Parameter value.
047   */
048  public final String value;
049
050  /**
051   * Creates a new parameter with the given {@code name} and {@code value}.
052   * 
053   * @param name
054   *          The parameter name.
055   * @param value
056   *          The parameter value.
057   * @param jsonMapper
058   *          Mapper for converting the parameter value to JSON.
059   * @throws IllegalArgumentException
060   *           If {@code name} is {@code null} or a blank string or either {@code value} or {@code jsonMapper} is
061   *           {@code null}.
062   */
063  private Parameter(String name, Object value, JsonMapper jsonMapper) {
064    if (isBlank(name) || value == null) {
065      throw new IllegalArgumentException(Parameter.class + " instances must have a non-blank name and non-null value."
066          + " Got instead name:" + name + ", value:" + value);
067    }
068
069    this.value = Optional.ofNullable(jsonMapper)
070      .orElseThrow(() -> new IllegalArgumentException("Provided " + JsonMapper.class + " must not be null."))
071      .toJson(value, true);
072    this.name = trimToEmpty(name);
073  }
074
075  /**
076   * Factory method which provides an instance with the given {@code name} and {@code value}.
077   * <p>
078   * The {@code value} parameter is often a {@link String} or primitive type like {@link Integer}, but you may pass in a
079   * {@link java.util.List}, {@link java.util.Map}, or your own <tt>@Facebook</tt>-annotated Javabean, and it will be
080   * converted to JSON automatically. See the "attachment" section of
081   * <a href="http://wiki.developers.facebook.com/index.php/Stream.publish">the stream.publish API documentation</a> for
082   * an example of where this is useful.
083   * 
084   * @param name
085   *          The parameter name.
086   * @param value
087   *          The parameter value.
088   * @return A {@code Parameter} instance with the given {@code name} and {@code value}.
089   * @throws IllegalArgumentException
090   *           If {@code name} or {@code value} is {@code null} or a blank string.
091   * @throws FacebookJsonMappingException
092   *           If an error occurs when converting {@code value} to JSON.
093   */
094  public static Parameter with(String name, Object value) {
095    return Parameter.with(name, value, new DefaultJsonMapper());
096  }
097
098  /**
099   * convenience factory method which needs a comma separated list of fields that the dev likes to fetch from the API
100   * 
101   * @param fieldList
102   *          comma separated list of fields
103   * @return Parameter object
104   */
105  public static Parameter withFields(String fieldList) {
106    return Parameter.with("fields", fieldList);
107  }
108
109  /**
110   * Convenience factory method that creates a {@code Parameter} object to retrieve the metadata from the API.
111   *
112   * @return Parameter object
113   */
114  public static Parameter withMetadata() {
115    return Parameter.with("metadata", "1");
116  }
117
118  /**
119   * convenience factory method which creates a {@code Parameter} object to fetch data from API with given locale
120   *
121   * @param locale
122   *          the locale that should be used to fetch the data
123   *
124   * @return Parameter object
125   */
126  public static Parameter withLocale(Locale locale) {
127    return Parameter.with("locale", locale.getLanguage());
128  }
129
130  /**
131   * convenience factory method which creates a {@code Parameter} object to fetch data from API with given limit
132   *
133   * @param limit
134   *          the limit that should be used fetching data
135   *
136   * @return Parameter object
137   */
138  public static Parameter withLimit(int limit) {
139    return Parameter.with("limit", limit);
140  }
141
142  /**
143   * convenience factory method which creates a {@code Parameter} object to post an object with a message parameter to
144   * the API
145   *
146   * @param obj
147   *          The content of the message, should be a String, but maybe some JSON
148   *
149   * @return Parameter object
150   */
151  public static Parameter withMessage(Object obj) {
152    return Parameter.with("message", obj);
153  }
154
155  /**
156   * convenience factory method which creates a {@code Parameter} object to query some information e.g. searching profiles
157   * the API
158   *
159   * @param queryString
160   *          the String used in the query
161   *
162   * @return Parameter object
163   */
164  public static Parameter withQuery(String queryString) {
165    return Parameter.with("q", queryString);
166  }
167
168  /**
169   * Factory method which provides an instance with the given {@code name} and {@code value}, using the provided
170   * {@code jsonMapper} to turn {@code value} into a JSON string.
171   * <p>
172   * The {@code value} parameter is often a {@link String} or primitive type like {@link Integer}, but you may pass in a
173   * {@link java.util.List}, {@link java.util.Map}, or your own <tt>@Facebook</tt>-annotated Javabean, and it will be
174   * converted to JSON automatically. See the "attachment" section of
175   * <a href="http://wiki.developers.facebook.com/index.php/Stream.publish">the stream.publish API documentation</a> for
176   * an example of where this is useful.
177   * 
178   * @param name
179   *          The parameter name.
180   * @param value
181   *          The parameter value.
182   * @param jsonMapper
183   *          The jsonMapper
184   * @return A {@code Parameter} instance with the given {@code name} and {@code value}.
185   * @throws IllegalArgumentException
186   *           If {@code name} or {@code value} is {@code null} or a blank string.
187   * @throws FacebookJsonMappingException
188   *           If an error occurs when converting {@code value} to JSON.
189   */
190  public static Parameter with(String name, Object value, JsonMapper jsonMapper) {
191    return new Parameter(name, value, jsonMapper);
192  }
193
194  /**
195   * @see java.lang.Object#equals(java.lang.Object)
196   */
197  @Override
198  public boolean equals(Object o) {
199    if (o == null || getClass() != o.getClass()) return false;
200    Parameter parameter = (Parameter) o;
201    return Objects.equals(name, parameter.name) && Objects.equals(value, parameter.value);
202  }
203
204  @Override
205  public int hashCode() {
206    int hash = 7;
207    hash = 37 * hash + this.name.hashCode();
208    hash = 41 * hash + this.value.hashCode();
209    return hash;
210  }
211
212  @Override
213  public String toString() {
214    return format("Parameter[%s=%s]", name, value);
215  }
216}