2424import com .fasterxml .jackson .databind .ObjectMapper ;
2525import java .io .IOException ;
2626import java .io .InputStream ;
27+ import java .util .ArrayList ;
2728import java .util .Arrays ;
2829import java .util .HashMap ;
2930import java .util .HashSet ;
31+ import java .util .List ;
3032import java .util .Locale ;
3133import java .util .Map ;
3234import java .util .Set ;
@@ -65,7 +67,7 @@ public final class DocumentationUtils {
6567 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper ();
6668
6769 private static final Logger log = Logger .loggerFor (DocumentationUtils .class );
68- private static Map <String , String > exampleUrlMap ;
70+ private static Map <String , JsonNode > serviceNodeCache ;
6971 private static Map <String , String > normalizedServiceKeyMap ;
7072
7173 private DocumentationUtils () {
@@ -158,23 +160,24 @@ public static String createLinkToServiceDocumentation(Metadata metadata, ShapeMo
158160 *
159161 * @param metadata the service metadata containing service name information
160162 * @param operationName the name of the operation to find an example for
163+ * @param exampleMetaPath the path to the example metadata JSON file
161164 * @return a '@see also' HTML link to the code example, or empty string if no example found
162165 */
163- public static String createLinkToCodeExample (Metadata metadata , String operationName ) {
166+ public static String createLinkToCodeExample (Metadata metadata , String operationName , String exampleMetaPath ) {
164167 try {
165168 String normalizedServiceName = metadata .getServiceName ().toLowerCase (Locale .ROOT );
166-
167- Map <String , String > normalizedMap = getNormalizedServiceKeyMap ();
169+ Map <String , String > normalizedMap = getNormalizedServiceKeyMap (exampleMetaPath );
168170 String actualServiceKey = normalizedMap .get (normalizedServiceName );
169171
170172 if (actualServiceKey != null ) {
171173 String targetExampleId = actualServiceKey + "_" + operationName ;
174+ JsonNode serviceNode = getServiceNode (actualServiceKey , exampleMetaPath );
172175
173- Map < String , String > urlMap = getExampleUrlMap ();
174- String url = urlMap . get ( targetExampleId );
175-
176- if ( url != null ) {
177- return String . format ( "<a href= \" %s \" target= \" _top \" >Code Example</a>" , url );
176+ if ( serviceNode != null ) {
177+ String url = findOperationUrl ( serviceNode , targetExampleId );
178+ if ( url != null ) {
179+ return String . format ( "<a href= \" %s \" target= \" _top \" >Code Example</a>" , url );
180+ }
178181 }
179182 }
180183
@@ -225,54 +228,54 @@ public static String defaultExistenceCheck() {
225228
226229
227230 /**
228- * Gets the cached example URL map for fast operation ID -> URL lookups.
231+ * Gets the cached service node
229232 */
230- private static Map < String , String > getExampleUrlMap ( ) {
231- if (exampleUrlMap == null ) {
232- buildExampleMaps ( );
233+ private static JsonNode getServiceNode ( String serviceKey , String exampleMetaPath ) {
234+ if (serviceNodeCache == null ) {
235+ buildServiceCache ( exampleMetaPath );
233236 }
234- return exampleUrlMap ;
237+ return serviceNodeCache . get ( serviceKey ) ;
235238 }
236239
237240 /**
238241 * Gets the cached normalized service key map for service name matching.
239242 */
240- private static Map <String , String > getNormalizedServiceKeyMap () {
243+ private static Map <String , String > getNormalizedServiceKeyMap (String exampleMetaPath ) {
241244 if (normalizedServiceKeyMap == null ) {
242- buildExampleMaps ( );
245+ buildServiceCache ( exampleMetaPath );
243246 }
244247 return normalizedServiceKeyMap ;
245248 }
246249
247250 /**
248- * Builds both the URL lookup map and normalized service key mapping from example-meta.json .
251+ * Builds the service node cache and normalized service key mapping from the specified example metadata file .
249252 */
250- private static void buildExampleMaps ( ) {
251- Map <String , String > urlMap = new HashMap <>();
253+ private static void buildServiceCache ( String exampleMetaPath ) {
254+ Map <String , JsonNode > nodeCache = new HashMap <>();
252255 Map <String , String > normalizedMap = new HashMap <>();
253256
254257 try (InputStream inputStream = DocumentationUtils .class .getClassLoader ()
255- .getResourceAsStream ("software/amazon/awssdk/codegen/example-meta.json" )) {
256-
258+ .getResourceAsStream (exampleMetaPath )) {
259+
257260 if (inputStream == null ) {
258- log .debug (() -> "example-meta.json not found in classpath" );
261+ log .debug (() -> exampleMetaPath + " not found in classpath" );
259262 } else {
260263 JsonNode root = OBJECT_MAPPER .readTree (inputStream );
261264 JsonNode servicesNode = root .get ("services" );
262265
263266 if (servicesNode != null ) {
264267 servicesNode .fieldNames ().forEachRemaining (serviceKey -> {
265268 buildNormalizedMapping (serviceKey , normalizedMap );
266- buildUrlMappingForService ( servicesNode .get (serviceKey ), urlMap );
269+ nodeCache . put ( serviceKey , servicesNode .get (serviceKey ));
267270 });
268271 }
269272 }
270273
271274 } catch (IOException e ) {
272- log .warn (() -> "Failed to load example-meta.json" , e );
275+ log .warn (() -> "Failed to load " + exampleMetaPath , e );
273276 }
274277
275- exampleUrlMap = urlMap ;
278+ serviceNodeCache = nodeCache ;
276279 normalizedServiceKeyMap = normalizedMap ;
277280 }
278281
@@ -285,9 +288,9 @@ private static void buildNormalizedMapping(String serviceKey, Map<String, String
285288 }
286289
287290 /**
288- * Builds URL mappings for all examples in a service.
291+ * Finds the URL for a specific operation ID within a service node .
289292 */
290- private static void buildUrlMappingForService (JsonNode serviceNode , Map < String , String > urlMap ) {
293+ private static String findOperationUrl (JsonNode serviceNode , String targetExampleId ) {
291294 JsonNode examplesNode = serviceNode .get ("examples" );
292295 if (examplesNode != null && examplesNode .isArray ()) {
293296 for (JsonNode example : examplesNode ) {
@@ -296,12 +299,100 @@ private static void buildUrlMappingForService(JsonNode serviceNode, Map<String,
296299
297300 if (idNode != null && urlNode != null ) {
298301 String id = idNode .asText ();
302+ if (targetExampleId .equals (id )) {
303+ return urlNode .asText ();
304+ }
305+ }
306+ }
307+ }
308+ return null ;
309+ }
310+
311+ /**
312+ * Gets all code examples for a specific service.
313+ *
314+ * @param metadata the service metadata containing service name information
315+ * @param exampleMetaPath the path to the example metadata JSON file
316+ * @return a list of examples for the service
317+ */
318+ public static List <ExampleData > getServiceCodeExamples (Metadata metadata , String exampleMetaPath ) {
319+ List <ExampleData > examples = new ArrayList <>();
320+
321+ try {
322+ String normalizedServiceName = metadata .getServiceName ().toLowerCase (Locale .ROOT );
323+ Map <String , String > normalizedMap = getNormalizedServiceKeyMap (exampleMetaPath );
324+ String actualServiceKey = normalizedMap .get (normalizedServiceName );
325+
326+ if (actualServiceKey != null ) {
327+ JsonNode serviceNode = getServiceNode (actualServiceKey , exampleMetaPath );
328+ if (serviceNode != null ) {
329+ examples = parseServiceExamples (serviceNode );
330+ }
331+ }
332+ } catch (Exception e ) {
333+ log .debug (() -> "Failed to load examples for " + metadata .getServiceName (), e );
334+ }
335+
336+ return examples ;
337+ }
338+
339+ /**
340+ * Parses examples from a service node in the JSON.
341+ */
342+ private static List <ExampleData > parseServiceExamples (JsonNode serviceNode ) {
343+ List <ExampleData > examples = new ArrayList <>();
344+ JsonNode examplesNode = serviceNode .get ("examples" );
345+
346+ if (examplesNode != null && examplesNode .isArray ()) {
347+ for (JsonNode example : examplesNode ) {
348+ JsonNode idNode = example .get ("id" );
349+ JsonNode titleNode = example .get ("title" );
350+ JsonNode categoryNode = example .get ("category" );
351+ JsonNode urlNode = example .get ("url" );
352+
353+ if (idNode != null && titleNode != null && urlNode != null ) {
354+ String id = idNode .asText ();
355+ String title = titleNode .asText ();
356+ String category = categoryNode != null ? categoryNode .asText () : "Api" ;
299357 String url = urlNode .asText ();
300- if (!id .isEmpty () && !url .isEmpty ()) {
301- urlMap .put (id , url );
358+
359+ if (!id .isEmpty () && !title .isEmpty () && !url .isEmpty ()) {
360+ examples .add (new ExampleData (id , title , category , url ));
302361 }
303362 }
304363 }
305364 }
365+
366+ return examples ;
367+ }
368+
369+ public static final class ExampleData {
370+ private final String id ;
371+ private final String title ;
372+ private final String category ;
373+ private final String url ;
374+
375+ public ExampleData (String id , String title , String category , String url ) {
376+ this .id = id ;
377+ this .title = title ;
378+ this .category = category ;
379+ this .url = url ;
380+ }
381+
382+ public String getId () {
383+ return id ;
384+ }
385+
386+ public String getTitle () {
387+ return title ;
388+ }
389+
390+ public String getCategory () {
391+ return category ;
392+ }
393+
394+ public String getUrl () {
395+ return url ;
396+ }
306397 }
307398}
0 commit comments