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.swagger; 018 019import static org.apache.juneau.common.utils.Utils.*; 020import static org.apache.juneau.internal.CollectionUtils.*; 021 022import java.util.*; 023 024import org.apache.juneau.common.utils.*; 025 026/** 027 * Map meant for method-name/operation mappings. 028 * 029 * <p> 030 * The OperationMap is a specialized TreeMap that represents the operations available on a single path in Swagger 2.0. 031 * It forces entries to be sorted in a specific order to ensure consistent output. This map is used within PathItem 032 * objects to define the HTTP methods and their corresponding operations. 033 * 034 * <h5 class='section'>Swagger Specification:</h5> 035 * <p> 036 * The OperationMap represents the operations field in a Path Item Object, where each key is an HTTP method and each 037 * value is an Operation object. The supported HTTP methods are: 038 * <ul class='spaced-list'> 039 * <li><c>get</c> ({@link Operation}) - A definition of a GET operation 040 * <li><c>put</c> ({@link Operation}) - A definition of a PUT operation 041 * <li><c>post</c> ({@link Operation}) - A definition of a POST operation 042 * <li><c>delete</c> ({@link Operation}) - A definition of a DELETE operation 043 * <li><c>options</c> ({@link Operation}) - A definition of an OPTIONS operation 044 * <li><c>head</c> ({@link Operation}) - A definition of a HEAD operation 045 * <li><c>patch</c> ({@link Operation}) - A definition of a PATCH operation 046 * </ul> 047 * 048 * <p> 049 * Forces entries to be sorted in the following order: 050 * <ul> 051 * <li><c>GET</c> 052 * <li><c>PUT</c> 053 * <li><c>POST</c> 054 * <li><c>DELETE</c> 055 * <li><c>OPTIONS</c> 056 * <li><c>HEAD</c> 057 * <li><c>PATCH</c> 058 * <li>Everything else. 059 * </ul> 060 * 061 * <h5 class='section'>Example:</h5> 062 * <p class='bjava'> 063 * <jc>// Construct using SwaggerBuilder.</jc> 064 * OperationMap <jv>operations</jv> = <jsm>operationMap</jsm>() 065 * .append(<js>"get"</js>, <jsm>operation</jsm>().setSummary(<js>"Get users"</js>)) 066 * .append(<js>"post"</jsm>, <jsm>operation</jsm>().setSummary(<js>"Create user"</js>)); 067 * 068 * <jc>// Serialize using JsonSerializer.</jc> 069 * String <jv>json</jv> = Json.<jsm>from</jsm>(<jv>operations</jv>); 070 * 071 * <jc>// Or just use toString() which does the same as above.</jc> 072 * <jv>json</jv> = <jv>operations</jv>.toString(); 073 * </p> 074 * <p class='bjson'> 075 * <jc>// Output</jc> 076 * { 077 * <js>"get"</js>: { <js>"summary"</js>: <js>"Get users"</js> }, 078 * <js>"post"</js>: { <js>"summary"</js>: <js>"Create user"</js> } 079 * } 080 * </p> 081 * 082 * <h5 class='section'>See Also:</h5><ul> 083 * <li class='link'><a class="doclink" href="https://swagger.io/specification/v2/#path-item-object">Swagger 2.0 Specification > Path Item Object</a> 084 * <li class='link'><a class="doclink" href="https://swagger.io/docs/specification/2-0/paths-and-operations/">Swagger Paths and Operations</a> 085 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauBeanSwagger2">juneau-bean-swagger-v2</a> 086 * </ul> 087 * 088 * @serial exclude 089 */ 090public class OperationMap extends TreeMap<String,Operation> { 091 private static final long serialVersionUID = 1L; 092 093 private static final Comparator<String> OP_SORTER = new Comparator<>() { 094 private final Map<String,String> methods = mapBuilder(String.class,String.class) 095 .add("get","0").add("put","1").add("post","2").add("delete","3").add("options","4").add("head","5").add("patch","6") 096 .build(); 097 098 @Override 099 public int compare(String o1, String o2) { 100 // Since keys are now stored in lowercase, we need to normalize them for comparison 101 var s1 = methods.get(emptyIfNull(o1).toLowerCase()); 102 var s2 = methods.get(emptyIfNull(o2).toLowerCase()); 103 if (s1 == null) 104 s1 = emptyIfNull(o1).toLowerCase(); 105 if (s2 == null) 106 s2 = emptyIfNull(o2).toLowerCase(); 107 return StringUtils.compare(s1, s2); 108 } 109 }; 110 111 /** 112 * Constructor. 113 */ 114 public OperationMap() { 115 super(OP_SORTER); 116 } 117 118 /** 119 * Override put to normalize keys to lowercase. 120 * 121 * @param key The key. 122 * @param value The value. 123 * @return The previous value associated with key, or null if there was no mapping for key. 124 */ 125 @Override 126 public Operation put(String key, Operation value) { 127 return super.put(emptyIfNull(key).toLowerCase(), value); 128 } 129 130 /** 131 * Fluent-style put method. 132 * 133 * @param httpMethodName The HTTP method name. 134 * @param operation The operation. 135 * @return This object. 136 */ 137 public OperationMap append(String httpMethodName, Operation operation) { 138 put(httpMethodName, operation); 139 return this; 140 } 141}