Skip to content
Open
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import software.amazon.awssdk.codegen.internal.DocumentationUtils;
import software.amazon.awssdk.codegen.model.intermediate.DocumentationModel;
import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel;
import software.amazon.awssdk.codegen.model.intermediate.OperationModel;
Expand Down Expand Up @@ -86,6 +87,11 @@ String getDocs() {
if (!crosslink.isEmpty()) {
docBuilder.see(crosslink);
}

String codeExampleLink = DocumentationUtils.createLinkToCodeExample(model.getMetadata(), opModel.getOperationName());
if (!codeExampleLink.isEmpty()) {
docBuilder.see(codeExampleLink);
}
return docBuilder.build().replace("$", "&#36");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,20 @@
import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Request;
import static software.amazon.awssdk.codegen.model.intermediate.ShapeType.Response;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import software.amazon.awssdk.codegen.model.intermediate.Metadata;
import software.amazon.awssdk.codegen.model.intermediate.ShapeModel;
import software.amazon.awssdk.utils.Logger;

public final class DocumentationUtils {

Expand Down Expand Up @@ -54,6 +62,9 @@ public final class DocumentationUtils {
"iot", "data.iot", "machinelearning", "rekognition", "s3", "sdb", "swf"
));
private static final Pattern COMMENT_DELIMITER = Pattern.compile("\\*\\/");

private static final Logger log = Logger.loggerFor(DocumentationUtils.class);
private static Map<String, String> exampleUrlMap;

private DocumentationUtils() {
}
Expand Down Expand Up @@ -140,6 +151,32 @@ public static String createLinkToServiceDocumentation(Metadata metadata, ShapeMo
: "";
}

/**
* Create a link to a code example for the given operation.
*
* @param metadata the service metadata containing service name information
* @param operationName the name of the operation to find an example for
* @return a '@see also' HTML link to the code example, or empty string if no example found
*/
public static String createLinkToCodeExample(Metadata metadata, String operationName) {
try {
String serviceKey = mapServiceNameToExampleKey(metadata.getServiceName());
String targetExampleId = serviceKey + "_" + operationName;

Map<String, String> urlMap = getExampleUrlMap();
String url = urlMap.get(targetExampleId);

if (url != null) {
return String.format("<a href=\"%s\" target=\"_top\">Code Example</a>", url);
}

return "";
} catch (Exception e) {
log.debug(() -> "Failed to create code example link for " + metadata.getServiceName() + "." + operationName, e);
return "";
}
}

public static String removeFromEnd(String string, String stringToRemove) {
return string.endsWith(stringToRemove) ? string.substring(0, string.length() - stringToRemove.length()) : string;
}
Expand Down Expand Up @@ -177,4 +214,73 @@ public static String defaultFluentReturn() {
public static String defaultExistenceCheck() {
return DEFAULT_EXISTENCE_CHECK;
}

/**
* Maps service names from codegen format (e.g., "AutoScaling") to example-meta.json keys (e.g., "auto-scaling").
*/
private static String mapServiceNameToExampleKey(String serviceName) {
if (serviceName == null) {
return "";
}

return serviceName
.replaceAll("([a-z0-9])([A-Z])", "$1-$2")
.toLowerCase(Locale.ROOT);
}

/**
* Gets the cached example URL map for fast operation ID -> URL lookups.
*/
private static Map<String, String> getExampleUrlMap() {
if (exampleUrlMap == null) {
exampleUrlMap = buildExampleUrlMap();
}
return exampleUrlMap;
}

/**
* Builds a flat lookup map from example-meta.json: operation ID -> URL
*/
private static Map<String, String> buildExampleUrlMap() {
Map<String, String> urlMap = new HashMap<>();

try (InputStream inputStream = DocumentationUtils.class.getClassLoader()
.getResourceAsStream("software/amazon/awssdk/codegen/example-meta.json")) {

if (inputStream == null) {
log.debug(() -> "example-meta.json not found in classpath");
return urlMap;
}

ObjectMapper objectMapper = new ObjectMapper();
JsonNode root = objectMapper.readTree(inputStream);

JsonNode servicesNode = root.get("services");
if (servicesNode != null) {
for (JsonNode serviceNode : servicesNode) {
JsonNode examplesNode = serviceNode.get("examples");
if (examplesNode != null && examplesNode.isArray()) {
for (JsonNode example : examplesNode) {
JsonNode idNode = example.get("id");
JsonNode urlNode = example.get("url");

if (idNode != null && urlNode != null) {
String id = idNode.asText();
String url = urlNode.asText();
if (!id.isEmpty() && !url.isEmpty()) {
urlMap.put(id, url);
}
}
}
}
}
}

return urlMap;

} catch (IOException e) {
log.warn(() -> "Failed to load example-meta.json", e);
return urlMap;
}
}
}
Loading
Loading