|
20 | 20 | import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Request; |
21 | 21 | import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Response; |
22 | 22 |
|
| 23 | +import com.fasterxml.jackson.databind.JsonNode; |
| 24 | +import com.fasterxml.jackson.databind.ObjectMapper; |
| 25 | +import java.io.IOException; |
| 26 | +import java.io.InputStream; |
23 | 27 | import java.util.Arrays; |
| 28 | +import java.util.HashMap; |
24 | 29 | import java.util.HashSet; |
| 30 | +import java.util.Locale; |
| 31 | +import java.util.Map; |
25 | 32 | import java.util.Set; |
26 | 33 | import java.util.regex.Pattern; |
27 | 34 | import software.amazon.awssdk.codegen.model.intermediate.Metadata; |
28 | 35 | import software.amazon.awssdk.codegen.model.intermediate.ShapeModel; |
| 36 | +import software.amazon.awssdk.utils.Logger; |
29 | 37 |
|
30 | 38 | public final class DocumentationUtils { |
31 | 39 |
|
@@ -54,6 +62,9 @@ public final class DocumentationUtils { |
54 | 62 | "iot", "data.iot", "machinelearning", "rekognition", "s3", "sdb", "swf" |
55 | 63 | )); |
56 | 64 | private static final Pattern COMMENT_DELIMITER = Pattern.compile("\\*\\/"); |
| 65 | + |
| 66 | + private static final Logger log = Logger.loggerFor(DocumentationUtils.class); |
| 67 | + private static Map<String, String> exampleUrlMap; |
57 | 68 |
|
58 | 69 | private DocumentationUtils() { |
59 | 70 | } |
@@ -140,6 +151,32 @@ public static String createLinkToServiceDocumentation(Metadata metadata, ShapeMo |
140 | 151 | : ""; |
141 | 152 | } |
142 | 153 |
|
| 154 | + /** |
| 155 | + * Create a link to a code example for the given operation. |
| 156 | + * |
| 157 | + * @param metadata the service metadata containing service name information |
| 158 | + * @param operationName the name of the operation to find an example for |
| 159 | + * @return a '@see also' HTML link to the code example, or empty string if no example found |
| 160 | + */ |
| 161 | + public static String createLinkToCodeExample(Metadata metadata, String operationName) { |
| 162 | + try { |
| 163 | + String serviceKey = mapServiceNameToExampleKey(metadata.getServiceName()); |
| 164 | + String targetExampleId = serviceKey + "_" + operationName; |
| 165 | + |
| 166 | + Map<String, String> urlMap = getExampleUrlMap(); |
| 167 | + String url = urlMap.get(targetExampleId); |
| 168 | + |
| 169 | + if (url != null) { |
| 170 | + return String.format("<a href=\"%s\" target=\"_top\">Code Example</a>", url); |
| 171 | + } |
| 172 | + |
| 173 | + return ""; |
| 174 | + } catch (Exception e) { |
| 175 | + log.debug(() -> "Failed to create code example link for " + metadata.getServiceName() + "." + operationName, e); |
| 176 | + return ""; |
| 177 | + } |
| 178 | + } |
| 179 | + |
143 | 180 | public static String removeFromEnd(String string, String stringToRemove) { |
144 | 181 | return string.endsWith(stringToRemove) ? string.substring(0, string.length() - stringToRemove.length()) : string; |
145 | 182 | } |
@@ -177,4 +214,73 @@ public static String defaultFluentReturn() { |
177 | 214 | public static String defaultExistenceCheck() { |
178 | 215 | return DEFAULT_EXISTENCE_CHECK; |
179 | 216 | } |
| 217 | + |
| 218 | + /** |
| 219 | + * Maps service names from codegen format (e.g., "AutoScaling") to example-meta.json keys (e.g., "auto-scaling"). |
| 220 | + */ |
| 221 | + private static String mapServiceNameToExampleKey(String serviceName) { |
| 222 | + if (serviceName == null) { |
| 223 | + return ""; |
| 224 | + } |
| 225 | + |
| 226 | + return serviceName |
| 227 | + .replaceAll("([a-z0-9])([A-Z])", "$1-$2") |
| 228 | + .toLowerCase(Locale.ROOT); |
| 229 | + } |
| 230 | + |
| 231 | + /** |
| 232 | + * Gets the cached example URL map for fast operation ID -> URL lookups. |
| 233 | + */ |
| 234 | + private static Map<String, String> getExampleUrlMap() { |
| 235 | + if (exampleUrlMap == null) { |
| 236 | + exampleUrlMap = buildExampleUrlMap(); |
| 237 | + } |
| 238 | + return exampleUrlMap; |
| 239 | + } |
| 240 | + |
| 241 | + /** |
| 242 | + * Builds a flat lookup map from example-meta.json: operation ID -> URL |
| 243 | + */ |
| 244 | + private static Map<String, String> buildExampleUrlMap() { |
| 245 | + Map<String, String> urlMap = new HashMap<>(); |
| 246 | + |
| 247 | + try (InputStream inputStream = DocumentationUtils.class.getClassLoader() |
| 248 | + .getResourceAsStream("software/amazon/awssdk/codegen/example-meta.json")) { |
| 249 | + |
| 250 | + if (inputStream == null) { |
| 251 | + log.debug(() -> "example-meta.json not found in classpath"); |
| 252 | + return urlMap; |
| 253 | + } |
| 254 | + |
| 255 | + ObjectMapper objectMapper = new ObjectMapper(); |
| 256 | + JsonNode root = objectMapper.readTree(inputStream); |
| 257 | + |
| 258 | + JsonNode servicesNode = root.get("services"); |
| 259 | + if (servicesNode != null) { |
| 260 | + for (JsonNode serviceNode : servicesNode) { |
| 261 | + JsonNode examplesNode = serviceNode.get("examples"); |
| 262 | + if (examplesNode != null && examplesNode.isArray()) { |
| 263 | + for (JsonNode example : examplesNode) { |
| 264 | + JsonNode idNode = example.get("id"); |
| 265 | + JsonNode urlNode = example.get("url"); |
| 266 | + |
| 267 | + if (idNode != null && urlNode != null) { |
| 268 | + String id = idNode.asText(); |
| 269 | + String url = urlNode.asText(); |
| 270 | + if (!id.isEmpty() && !url.isEmpty()) { |
| 271 | + urlMap.put(id, url); |
| 272 | + } |
| 273 | + } |
| 274 | + } |
| 275 | + } |
| 276 | + } |
| 277 | + } |
| 278 | + |
| 279 | + return urlMap; |
| 280 | + |
| 281 | + } catch (IOException e) { |
| 282 | + log.warn(() -> "Failed to load example-meta.json", e); |
| 283 | + return urlMap; |
| 284 | + } |
| 285 | + } |
180 | 286 | } |
0 commit comments