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("\\*\\/", "*&#47;");
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