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.bean.openapi3; 018 019import static org.apache.juneau.common.utils.Utils.*; 020import static org.apache.juneau.internal.CollectionUtils.*; 021import static org.apache.juneau.internal.ConverterUtils.*; 022 023import java.util.*; 024 025import org.apache.juneau.common.utils.*; 026import org.apache.juneau.internal.*; 027 028/** 029 * The Link object represents a possible design-time link for a response. 030 * 031 * <p> 032 * The Link Object represents a possible design-time link for a response. The presence of a link does not guarantee 033 * the caller's ability to successfully invoke it, rather it provides a known relationship and traversal mechanism 034 * between responses and other operations. 035 * 036 * <h5 class='section'>OpenAPI Specification:</h5> 037 * <p> 038 * The Link Object is composed of the following fields: 039 * <ul class='spaced-list'> 040 * <li><c>operationRef</c> (string) - A relative or absolute reference to an OAS operation (mutually exclusive with <c>operationId</c>) 041 * <li><c>operationId</c> (string) - The name of an existing, resolvable OAS operation (mutually exclusive with <c>operationRef</c>) 042 * <li><c>parameters</c> (map of any) - A map representing parameters to pass to an operation as specified with <c>operationId</c> or identified via <c>operationRef</c> 043 * <li><c>requestBody</c> (any) - A literal value or expression to use as a request body when calling the target operation 044 * <li><c>description</c> (string) - A description of the link (CommonMark syntax may be used) 045 * <li><c>server</c> ({@link Server}) - A server object to be used by the target operation 046 * </ul> 047 * 048 * <h5 class='section'>Example:</h5> 049 * <p class='bjava'> 050 * <jc>// Create a link to another operation</jc> 051 * Link <jv>link</jv> = <jk>new</jk> Link() 052 * .setOperationId(<js>"getUserById"</js>) 053 * .setParameters( 054 * JsonMap.<jsm>of</jsm>(<js>"userId"</js>, <js>"$response.body#/id"</js>) 055 * ) 056 * .setDescription(<js>"The id value returned in the response can be used as userId parameter in GET /users/{userId}"</js>); 057 * </p> 058 * 059 * <h5 class='section'>See Also:</h5><ul> 060 * <li class='link'><a class="doclink" href="https://spec.openapis.org/oas/v3.0.0#link-object">OpenAPI Specification > Link Object</a> 061 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/links/">OpenAPI Links</a> 062 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanOpenApi3">juneau-bean-openapi-v3</a> 063 * </ul> 064 */ 065public class Link extends OpenApiElement { 066 067 private String operationRef; 068 private String operationId; 069 private String description; 070 private Object requestBody; 071 private Server server; 072 private Map<String,Object> parameters; 073 074 /** 075 * Default constructor. 076 */ 077 public Link() {} 078 079 /** 080 * Copy constructor. 081 * 082 * @param copyFrom The object to copy. 083 */ 084 public Link(Link copyFrom) { 085 super(copyFrom); 086 087 this.operationRef = copyFrom.operationRef; 088 this.description = copyFrom.description; 089 this.operationId = copyFrom.operationId; 090 this.requestBody = copyFrom.requestBody; 091 this.server = copyFrom.server == null ? null : copyFrom.server.copy(); 092 this.parameters = copyOf(copyFrom.parameters); 093 } 094 095 /** 096 * Make a deep copy of this object. 097 * 098 * @return A deep copy of this object. 099 */ 100 public Link copy() { 101 return new Link(this); 102 } 103 104 /** 105 * Bean property getter: <property>operationRef</property>. 106 * 107 * <p> 108 * The identifying name of the contact person/organization. 109 * 110 * @return The property value, or <jk>null</jk> if it is not set. 111 */ 112 public String getOperationRef() { 113 return operationRef; 114 } 115 116 /** 117 * Bean property setter: <property>operationRef</property>. 118 * 119 * <p> 120 * The identifying name of the contact person/organization. 121 * 122 * @param value 123 * The new value for this property. 124 * <br>Can be <jk>null</jk> to unset the property. 125 * @return This object 126 */ 127 public Link setOperationRef(String value) { 128 operationRef = value; 129 return this; 130 } 131 132 /** 133 * Bean property getter: <property>description</property>. 134 * 135 * <p> 136 * The URL pointing to the contact information. 137 * 138 * @return The property value, or <jk>null</jk> if it is not set. 139 */ 140 public String getDescription() { 141 return description; 142 } 143 144 /** 145 * Bean property setter: <property>description</property>. 146 * @param value 147 * The new value for this property. 148 * <br>Can be <jk>null</jk> to unset the property. 149 * @return This object 150 */ 151 public Link setDescription(String value) { 152 description = value; 153 return this; 154 } 155 156 /** 157 * Bean property getter: <property>externalValue</property>. 158 * 159 * <p> 160 * The email address of the contact person/organization. 161 * 162 * @return The property value, or <jk>null</jk> if it is not set. 163 */ 164 public String getOperationId() { 165 return operationId; 166 } 167 168 /** 169 * Bean property setter: <property>externalValue</property>. 170 * 171 * <p> 172 * The email address of the contact person/organization. 173 * 174 * @param value 175 * The new value for this property. 176 * <br>MUST be in the format of an email address. 177 * <br>Can be <jk>null</jk> to unset the property. 178 * @return This object 179 */ 180 public Link setOperationId(String value) { 181 operationId = value; 182 return this; 183 } 184 185 /** 186 * Bean property getter: <property>default</property>. 187 * 188 * <p> 189 * Declares the value of the parameter that the server will use if none is provided, for example a <js>"count"</js> 190 * to control the number of results per page might default to 100 if not supplied by the client in the request. 191 * 192 * (Note: <js>"value"</js> has no meaning for required parameters.) 193 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for this parameter. 194 * 195 * @return The property value, or <jk>null</jk> if it is not set. 196 */ 197 public Object getRequestBody() { 198 return requestBody; 199 } 200 201 /** 202 * Bean property setter: <property>value</property>. 203 * 204 * <p> 205 * Declares the value of the parameter that the server will use if none is provided, for example a <js>"count"</js> 206 * to control the number of results per page might default to 100 if not supplied by the client in the request. 207 * (Note: <js>"default"</js> has no meaning for required parameters.) 208 * Unlike JSON Schema this value MUST conform to the defined <code>type</code> for this parameter. 209 * 210 * @param val The new value for this property. 211 * <br>Can be <jk>null</jk> to unset the property. 212 * @return This object 213 */ 214 public Link setRequestBody(Object val) { 215 requestBody = val; 216 return this; 217 } 218 219 /** 220 * Bean property getter: <property>additionalProperties</property>. 221 * 222 * @return The property value, or <jk>null</jk> if it is not set. 223 */ 224 public Server getServer() { 225 return server; 226 } 227 228 /** 229 * Bean property setter: <property>additionalProperties</property>. 230 * 231 * @param value 232 * The new value for this property. 233 * <br>Can be <jk>null</jk> to unset the property. 234 * @return This object 235 */ 236 public Link setServer(Server value) { 237 server = value; 238 return this; 239 } 240 241 /** 242 * Bean property getter: <property>examples</property>. 243 * 244 * <p> 245 * An example of the response message. 246 * 247 * @return The property value, or <jk>null</jk> if it is not set. 248 */ 249 public Map<String,Object> getParameters() { 250 return parameters; 251 } 252 253 /** 254 * Bean property setter: <property>examples</property>. 255 * 256 * <p> 257 * An example of the response message. 258 * 259 * @param value 260 * The new value for this property. 261 * <br>Keys must be MIME-type strings. 262 * <br>Can be <jk>null</jk> to unset the property. 263 * @return This object 264 */ 265 public Link setParameters(Map<String,Object> value) { 266 parameters = copyOf(value); 267 return this; 268 } 269 270 /** 271 * Adds a single value to the <property>examples</property> property. 272 * 273 * @param mimeType The mime-type string. Must not be <jk>null</jk>. 274 * @param parameter The example. Must not be <jk>null</jk>. 275 * @return This object 276 */ 277 public Link addParameter(String mimeType, Object parameter) { 278 assertArgNotNull("mimeType", mimeType); 279 assertArgNotNull("parameter", parameter); 280 parameters = mapBuilder(parameters).sparse().add(mimeType, parameter).build(); 281 return this; 282 } 283 284 @Override /* Overridden from OpenApiElement */ 285 public <T> T get(String property, Class<T> type) { 286 assertArgNotNull("property", property); 287 return switch (property) { 288 case "description" -> toType(getDescription(), type); 289 case "operationRef" -> toType(getOperationRef(), type); 290 case "operationId" -> toType(getOperationId(), type); 291 case "requestBody" -> toType(getRequestBody(), type); 292 case "parameters" -> toType(getParameters(), type); 293 case "server" -> toType(getServer(), type); 294 default -> super.get(property, type); 295 }; 296 } 297 298 @Override /* Overridden from OpenApiElement */ 299 public Link set(String property, Object value) { 300 assertArgNotNull("property", property); 301 return switch (property) { 302 case "description" -> setDescription(Utils.s(value)); 303 case "operationId" -> setOperationId(Utils.s(value)); 304 case "operationRef" -> setOperationRef(Utils.s(value)); 305 case "parameters" -> setParameters(mapBuilder(String.class, Object.class).sparse().addAny(value).build()); 306 case "requestBody" -> setRequestBody(value); 307 case "server" -> setServer(toType(value, Server.class)); 308 default -> { 309 super.set(property, value); 310 yield this; 311 } 312 }; 313 } 314 315 @Override /* Overridden from OpenApiElement */ 316 public Set<String> keySet() { 317 var s = setBuilder(String.class) 318 .addIf(description != null, "description") 319 .addIf(operationId != null, "operationId") 320 .addIf(operationRef != null, "operationRef") 321 .addIf(parameters != null, "parameters") 322 .addIf(requestBody != null, "requestBody") 323 .addIf(server != null, "server") 324 .build(); 325 return new MultiSet<>(s, super.keySet()); 326 } 327 328 @Override /* Overridden from OpenApiElement */ 329 public Link strict() { 330 super.strict(); 331 return this; 332 } 333 334 @Override /* Overridden from OpenApiElement */ 335 public Link strict(Object value) { 336 super.strict(value); 337 return this; 338 } 339 340}