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.internal.ClassUtils.*;
020
021import java.util.*;
022import java.util.function.*;
023
024import org.apache.http.*;
025import org.apache.juneau.*;
026import org.apache.juneau.annotation.*;
027import org.apache.juneau.assertions.*;
028import org.apache.juneau.common.utils.*;
029import org.apache.juneau.http.header.*;
030import org.apache.juneau.internal.*;
031import org.apache.juneau.reflect.*;
032
033/**
034 * Implementation of {@link NameValuePair} for serializing POJOs as URL-encoded form post entries.
035 *
036 * Provides the following features:
037 * <ul class='spaced-list'>
038 *    <li>
039 *       Values from {@link Supplier Suppliers}.
040 *    <li>
041 *       Caching.
042 *    <li>
043 *       Fluent setters.
044 *    <li>
045 *       Fluent assertions.
046 * </ul>
047 *
048 * <h5 class='section'>See Also:</h5><ul>
049 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauRestCommonBasics">juneau-rest-common Basics</a>
050 * </ul>
051 */
052@BeanIgnore
053public class BasicPart implements NameValuePair, Headerable {
054   private final String name;
055   private final Object value;
056
057   /**
058    * Static creator.
059    *
060    * @param name The part name.
061    * @param value The part value.
062    * @return A new {@link BasicPart} object.
063    */
064   public static BasicPart of(String name, Object value) {
065      return new BasicPart(name, value);
066   }
067
068   /**
069    * Creates a {@link NameValuePair} from a name/value pair string (e.g. <js>"Foo: bar"</js>)
070    *
071    * @param pair The pair string.
072    * @return A new {@link NameValuePair} object.
073    */
074   public static BasicPart ofPair(String pair) {
075      if (pair == null)
076         return null;
077      int i = pair.indexOf(':');
078      if (i == -1)
079         i = pair.indexOf('=');
080      if (i == -1)
081         return of(pair, "");
082      return of(pair.substring(0,i).trim(), pair.substring(i+1).trim());
083   }
084
085   /**
086    * Utility method for converting an arbitrary object to a {@link NameValuePair}.
087    *
088    * @param o
089    *    The object to cast or convert to a {@link NameValuePair}.
090    * @return Either the same object cast as a {@link NameValuePair} or converted to a {@link NameValuePair}.
091    */
092   @SuppressWarnings("rawtypes")
093   public static NameValuePair cast(Object o) {
094      if (o instanceof NameValuePair)
095         return (NameValuePair)o;
096      if (o instanceof NameValuePairable)
097         return ((NameValuePairable)o).asNameValuePair();
098      if (o instanceof NameValuePair) {
099         NameValuePair p = (NameValuePair)o;
100         return BasicPart.of(p.getName(), p.getValue());
101      }
102      if (o instanceof Headerable) {
103         Header x = ((Headerable)o).asHeader();
104         return BasicPart.of(x.getName(), x.getValue());
105      }
106      if (o instanceof Map.Entry) {
107         Map.Entry e = (Map.Entry)o;
108         return BasicPart.of(Utils.s(e.getKey()), e.getValue());
109      }
110      throw new BasicRuntimeException("Object of type {0} could not be converted to a Part.", className(o));
111   }
112
113   /**
114    * Returns <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
115    *
116    * @param o The object to check.
117    * @return <jk>true</jk> if the {@link #cast(Object)} method can be used on the specified object.
118    */
119   public static boolean canCast(Object o) {
120      ClassInfo ci = ClassInfo.of(o);
121      return ci != null && ci.isChildOfAny(Headerable.class, NameValuePair.class, NameValuePairable.class, Map.Entry.class);
122   }
123
124   /**
125    * Constructor.
126    *
127    * @param name The part name.
128    * @param value The POJO to serialize to The part value.
129    */
130   public BasicPart(String name, Object value) {
131      this.name = name;
132      this.value = value;
133   }
134
135   /**
136    * Copy constructor.
137    *
138    * @param copyFrom The object to copy.
139    */
140   protected BasicPart(BasicPart copyFrom) {
141      Utils.assertArgNotNull("copyFrom", copyFrom);
142      this.name = copyFrom.name;
143      this.value = copyFrom.value;
144   }
145
146   /**
147    * Provides an object for performing assertions against the name of this pair.
148    *
149    * @return An object for performing assertions against the name of this pair.
150    */
151   public FluentStringAssertion<BasicPart> assertName() {
152      return new FluentStringAssertion<>(getName(), this);
153   }
154
155   /**
156    * Provides an object for performing assertions against the value of this pair.
157    *
158    * @return An object for performing assertions against the value of this pair.
159    */
160   public FluentStringAssertion<BasicPart> assertValue() {
161      return new FluentStringAssertion<>(getValue(), this);
162   }
163
164   @Override /* Headerable */
165   public BasicHeader asHeader() {
166      return BasicHeader.of(name, Utils.s(value));
167   }
168
169   @Override /* NameValuePair */
170   public String getName() {
171      return name;
172   }
173
174   @Override /* NameValuePair */
175   public String getValue() {
176      return Utils.s(unwrap(value));
177   }
178
179   /**
180    * Returns the raw value of the part.
181    *
182    * @return The raw value of the part.
183    */
184   public Object getRawValue() {
185      return unwrap(value);
186   }
187
188   @Override /* Object */
189   public String toString() {
190      return getName() + "=" + getValue();
191   }
192
193   private Object unwrap(Object o) {
194      while (o instanceof Supplier)
195         o = ((Supplier<?>)o).get();
196      return o;
197   }
198}