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