1 /* 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"). 5 * You may not use this file except in compliance with the License. 6 * A copy of the License is located at 7 * 8 * http://aws.amazon.com/apache2.0 9 * 10 * or in the "license" file accompanying this file. This file is distributed 11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 * express or implied. See the License for the specific language governing 13 * permissions and limitations under the License. 14 */ 15 16 package software.amazon.awssdk.codegen.internal; 17 18 import static software.amazon.awssdk.codegen.internal.Constant.AWS_DOCS_HOST; 19 import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Model; 20 import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Request; 21 import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Response; 22 23 import java.util.Arrays; 24 import java.util.HashSet; 25 import java.util.Set; 26 import software.amazon.awssdk.codegen.model.intermediate.Metadata; 27 import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; 28 29 public final class DocumentationUtils { 30 31 private static final String DEFAULT_SETTER = "Sets the value of the %s property for this object."; 32 33 private static final String DEFAULT_SETTER_PARAM = "The new value for the %s property for this object."; 34 35 private static final String DEFAULT_GETTER = "Returns the value of the %s property for this object."; 36 37 private static final String DEFAULT_GETTER_PARAM = "The value of the %s property for this object."; 38 39 private static final String DEFAULT_EXISTENCE_CHECK = 40 "For responses, this returns true if the service returned a value for the %s property. This DOES NOT check that the " 41 + "value is non-empty (for which, you should check the {@code isEmpty()} method on the property). This is useful because " 42 + "the SDK will never return a null collection or map, but you may need to differentiate between the service returning " 43 + "nothing (or null) and the service returning an empty collection or map. For requests, this returns true if a value " 44 + "for the property was specified in the request builder, and false if a value was not specified."; 45 46 private static final String DEFAULT_FLUENT_RETURN = 47 "Returns a reference to this object so that method calls can be chained together."; 48 49 //TODO probably should move this to a custom config in each service 50 private static final Set<String> SERVICES_EXCLUDED_FROM_CROSS_LINKING = new HashSet<>(Arrays.asList( 51 "apigateway", "budgets", "cloudsearch", "cloudsearchdomain", 52 "discovery", "elastictranscoder", "es", "glacier", 53 "iot", "data.iot", "machinelearning", "rekognition", "s3", "sdb", "swf" 54 )); 55 DocumentationUtils()56 private DocumentationUtils() { 57 } 58 59 /** 60 * Returns a documentation with HTML tags prefixed and suffixed removed, or 61 * returns empty string if the input is empty or null. This method is to be 62 * used when constructing documentation for method parameters. 63 * 64 * @param documentation 65 * unprocessed input documentation 66 * @return HTML tag stripped documentation or empty string if input was 67 * null. 68 */ stripHtmlTags(String documentation)69 public static String stripHtmlTags(String documentation) { 70 if (documentation == null) { 71 return ""; 72 } 73 74 if (documentation.startsWith("<")) { 75 int startTagIndex = documentation.indexOf('>'); 76 int closingTagIndex = documentation.lastIndexOf('<'); 77 if (closingTagIndex > startTagIndex) { 78 documentation = stripHtmlTags(documentation.substring(startTagIndex + 1, closingTagIndex)); 79 } else { 80 documentation = stripHtmlTags(documentation.substring(startTagIndex + 1)); 81 } 82 } 83 84 return documentation.trim(); 85 } 86 87 /** 88 * Escapes Java comment breaking illegal character sequences. 89 * 90 * @param documentation 91 * unprocessed input documentation 92 * @return escaped documentation, or empty string if input was null 93 */ escapeIllegalCharacters(String documentation)94 public static String escapeIllegalCharacters(String documentation) { 95 if (documentation == null) { 96 return ""; 97 } 98 99 /* 100 * this specifically handles a case where a '* /' sequence may 101 * be present in documentation and inadvertently terminate that Java 102 * comment line, resulting in broken code. 103 */ 104 documentation = documentation.replaceAll("\\*\\/", "*/"); 105 106 return documentation; 107 } 108 109 /** 110 * Create the HTML for a link to the operation/shape core AWS docs site 111 * 112 * @param metadata the UID for the service from that services metadata 113 * @param name the name of the shape/request/operation 114 * 115 * @return a '@see also' HTML link to the doc 116 */ createLinkToServiceDocumentation(Metadata metadata, String name)117 public static String createLinkToServiceDocumentation(Metadata metadata, String name) { 118 if (isCrossLinkingEnabledForService(metadata)) { 119 return String.format("<a href=\"https://%s/goto/WebAPI/%s/%s\" target=\"_top\">AWS API Documentation</a>", 120 AWS_DOCS_HOST, 121 metadata.getUid(), 122 name); 123 } 124 return ""; 125 } 126 127 /** 128 * Create the HTML for a link to the operation/shape core AWS docs site 129 * 130 * @param metadata the UID for the service from that services metadata 131 * @param shapeModel the model of the shape 132 * 133 * @return a '@see also' HTML link to the doc 134 */ createLinkToServiceDocumentation(Metadata metadata, ShapeModel shapeModel)135 public static String createLinkToServiceDocumentation(Metadata metadata, ShapeModel shapeModel) { 136 return isRequestResponseOrModel(shapeModel) ? createLinkToServiceDocumentation(metadata, 137 shapeModel.getDocumentationShapeName()) 138 : ""; 139 } 140 removeFromEnd(String string, String stringToRemove)141 public static String removeFromEnd(String string, String stringToRemove) { 142 return string.endsWith(stringToRemove) ? string.substring(0, string.length() - stringToRemove.length()) : string; 143 } 144 isRequestResponseOrModel(ShapeModel shapeModel)145 private static boolean isRequestResponseOrModel(ShapeModel shapeModel) { 146 return shapeModel.getShapeType() == Model || shapeModel.getShapeType() == Request || 147 shapeModel.getShapeType() == Response; 148 } 149 isCrossLinkingEnabledForService(Metadata metadata)150 private static boolean isCrossLinkingEnabledForService(Metadata metadata) { 151 return metadata.getUid() != null && metadata.getEndpointPrefix() != null && 152 !SERVICES_EXCLUDED_FROM_CROSS_LINKING.contains(metadata.getEndpointPrefix()); 153 } 154 defaultSetter()155 public static String defaultSetter() { 156 return DEFAULT_SETTER; 157 } 158 defaultSetterParam()159 public static String defaultSetterParam() { 160 return DEFAULT_SETTER_PARAM; 161 } 162 defaultGetter()163 public static String defaultGetter() { 164 return DEFAULT_GETTER; 165 } 166 defaultGetterParam()167 public static String defaultGetterParam() { 168 return DEFAULT_GETTER_PARAM; 169 } 170 defaultFluentReturn()171 public static String defaultFluentReturn() { 172 return DEFAULT_FLUENT_RETURN; 173 } 174 defaultExistenceCheck()175 public static String defaultExistenceCheck() { 176 return DEFAULT_EXISTENCE_CHECK; 177 } 178 } 179