001// ***************************************************************************************************************************
002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
003// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
005// * with the License.  You may obtain a copy of the License at                                                              *
006// *                                                                                                                         *
007// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
008// *                                                                                                                         *
009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
011// * specific language governing permissions and limitations under the License.                                              *
012// ***************************************************************************************************************************
013package org.apache.juneau.http;
014
015import static org.apache.juneau.internal.StringUtils.*;
016
017import java.util.*;
018import java.util.function.*;
019
020import org.apache.http.*;
021import org.apache.juneau.*;
022import org.apache.juneau.annotation.*;
023import org.apache.juneau.assertions.*;
024import org.apache.juneau.reflect.*;
025
026/**
027 * Subclass of {@link NameValuePair} for serializing POJOs as URL-encoded form post entries.
028 *
029 * Provides the following features:
030 * <ul class='spaced-list'>
031 *    <li>
032 *       Values from {@link Supplier Suppliers}.
033 *    <li>
034 *       Caching.
035 *    <li>
036 *       Fluent setters.
037 *    <li>
038 *       Fluent assertions.
039 * </ul>
040 */
041@BeanIgnore
042public class BasicNameValuePair implements NameValuePair, Headerable {
043   private final String name;
044   private final Object value;
045
046   /**
047    * Convenience creator.
048    *
049    * @param name The parameter name.
050    * @param value The parameter value.
051    * @return A new {@link BasicNameValuePair} object.
052    */
053   public static BasicNameValuePair of(String name, Object value) {
054      return new BasicNameValuePair(name, value);
055   }
056
057   /**
058    * Creates a {@link NameValuePair} from a name/value pair string (e.g. <js>"Foo: bar"</js>)
059    *
060    * @param pair The pair string.
061    * @return A new {@link NameValuePair} object.
062    */
063   public static BasicNameValuePair ofPair(String pair) {
064      if (pair == null)
065         return null;
066      int i = pair.indexOf(':');
067      if (i == -1)
068         return of(pair, "");
069      return of(pair.substring(0,i).trim(), pair.substring(i+1).trim());
070   }
071
072   /**
073    * Convenience creator using supplier.
074    *
075    * <p>
076    * Value is re-evaluated on each call to {@link #getValue()}.
077    *
078    * @param name The parameter name.
079    * @param value The parameter value supplier.
080    * @return A new {@link BasicNameValuePair} object.
081    */
082   public static BasicNameValuePair of(String name, Supplier<?> value) {
083      return new BasicNameValuePair(name, value);
084   }
085
086   /**
087    * Utility method for converting an arbitrary object to a {@link NameValuePair}.
088    *
089    * @param o
090    *    The object to cast or convert to a {@link NameValuePair}.
091    * @return Either the same object cast as a {@link NameValuePair} or converted to a {@link NameValuePair}.
092    */
093   @SuppressWarnings("rawtypes")
094   public static NameValuePair cast(Object o) {
095      if (o instanceof NameValuePair)
096         return (NameValuePair)o;
097      if (o instanceof NameValuePairable)
098         return ((NameValuePairable)o).asNameValuePair();
099      if (o instanceof Headerable)
100         return ((Headerable)o).asHeader();
101      if (o instanceof Map.Entry) {
102         Map.Entry e = (Map.Entry)o;
103         return BasicNameValuePair.of(stringify(e.getKey()), e.getValue());
104      }
105      throw new BasicRuntimeException("Object of type {0} could not be converted to a NameValuePair.", o == null ? null : o.getClass().getName());
106   }
107
108   /**
109    * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
110    *
111    * @param o The object to check.
112    * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
113    */
114   public static boolean canCast(Object o) {
115      ClassInfo ci = ClassInfo.of(o);
116      return ci != null && ci.isChildOfAny(Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class);
117   }
118
119   /**
120    * Constructor.
121    *
122    * @param name The parameter name.
123    * @param value The POJO to serialize to the parameter value.
124    */
125   public BasicNameValuePair(String name, Object value) {
126      this.name = name;
127      this.value = value;
128   }
129
130   /**
131    * Provides an object for performing assertions against the name of this pair.
132    *
133    * @return An object for performing assertions against the name of this pair.
134    */
135   public FluentStringAssertion<BasicNameValuePair> assertName() {
136      return new FluentStringAssertion<>(getName(), this);
137   }
138
139   /**
140    * Provides an object for performing assertions against the value of this pair.
141    *
142    * @return An object for performing assertions against the value of this pair.
143    */
144   public FluentStringAssertion<BasicNameValuePair> assertValue() {
145      return new FluentStringAssertion<>(getValue(), this);
146   }
147
148   @Override /* Headerable */
149   public BasicHeader asHeader() {
150      return BasicHeader.of(name, value);
151   }
152
153   @Override /* NameValuePair */
154   public String getName() {
155      return name;
156   }
157
158   @Override /* NameValuePair */
159   public String getValue() {
160      return stringify(unwrap(value));
161   }
162
163   @Override /* Object */
164   public String toString() {
165      return urlEncode(getName()) + "=" + urlEncode(getValue());
166   }
167
168   private Object unwrap(Object o) {
169      while (o instanceof Supplier)
170         o = ((Supplier<?>)o).get();
171      return o;
172   }
173
174   // <FluentSetters>
175
176   // </FluentSetters>
177}