001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.juneau.rest.server.tracing.otel; 018 019import static org.apache.juneau.commons.utils.StringUtils.*; 020 021import java.util.*; 022 023import org.apache.juneau.rest.server.*; 024 025import io.opentelemetry.context.propagation.*; 026 027/** 028 * {@link TextMapGetter} implementation that reads HTTP request headers from a {@link RestRequest}. 029 * 030 * <p> 031 * Used by {@link OtelTracerHook} to extract W3C {@code traceparent} / {@code tracestate} headers (and 032 * any other propagator-defined headers, e.g. baggage) from incoming requests so the server span can 033 * be created as a child of the caller's trace context. 034 * 035 * <p> 036 * Header lookups are case-insensitive at the underlying {@code RequestHeaderList}, matching the 037 * RFC 9110 contract. 038 * 039 * @since 10.0.0 040 */ 041@SuppressWarnings({ 042 "java:S6548" // Singleton pattern is intentional; INSTANCE is a stateless, thread-safe TextMapGetter implementation. 043}) 044public final class RestRequestTextMapGetter implements TextMapGetter<RestRequest> { 045 046 /** Process-wide singleton instance. */ 047 public static final RestRequestTextMapGetter INSTANCE = new RestRequestTextMapGetter(); 048 049 private RestRequestTextMapGetter() {} 050 051 @Override /* TextMapGetter */ 052 public Iterable<String> keys(RestRequest carrier) { 053 if (carrier == null) 054 return List.of(); 055 return carrier.getHeaders().getNames(); 056 } 057 058 @Override /* TextMapGetter */ 059 public String get(RestRequest carrier, String key) { 060 if (carrier == null || key == null) 061 return null; 062 var header = carrier.getHeaderParam(key); 063 if (! header.isPresent()) 064 return null; 065 var value = header.orElse(null); 066 return isEmpty(value) ? null : value; 067 } 068}