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}