diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java index f58a8042b..4b2a0c415 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/HttpClientContext.java @@ -53,6 +53,8 @@ import org.apache.hc.core5.http.config.Lookup; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpCoreContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Client execution {@link HttpContext}. This class can be re-used for @@ -66,6 +68,8 @@ */ public class HttpClientContext extends HttpCoreContext { + private static final Logger LOG = LoggerFactory.getLogger(HttpClientContext.class); + /** * @deprecated Use getter methods */ @@ -394,13 +398,30 @@ public T getUserToken(final Class clazz) { } /** - * Represents an arbitrary user token that identifies the user in the context - * of the request execution. + * Retrieves the user token associated with this context. *

- * This context attribute can be set by the caller. + * This method checks the internal user token field first. If it's not set, + * it falls back to retrieving the token from the context attributes for + * backward compatibility. It is strongly recommended to use + * {@link #setUserToken(Object)} for setting the user token, rather than + * manipulating context attributes directly. + *

+ * + * @return the user token associated with this context, or {@code null} if not set. */ public Object getUserToken() { - return userToken; + // For backward compatibility, check the internal userToken field first + if (userToken != null) { + return userToken; + } + + if (LOG.isWarnEnabled()) { + LOG.warn("Retrieving user token from context attributes for backward compatibility. " + + "It is strongly recommended to use 'setUserToken(Object)' to set the user token."); + } + + // Fall back to context attributes for compatibility with older versions + return super.getAttribute(USER_TOKEN); } public void setUserToken(final Object userToken) { @@ -436,6 +457,7 @@ public void setRequestConfig(final RequestConfig requestConfig) { * in the given context. *

* This context attribute is expected to be populated by the protocol handler. + * * @since 5.1 */ public String getExchangeId() { @@ -585,6 +607,7 @@ public Object getUserToken() { @Override public void setUserToken(final Object userToken) { httpContext.setAttribute(USER_TOKEN, userToken); + super.setUserToken(userToken); } @Override diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestHttpClientContext.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestHttpClientContext.java new file mode 100644 index 000000000..c2e28fcd8 --- /dev/null +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestHttpClientContext.java @@ -0,0 +1,49 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.client5.http.impl.classic; + +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.core5.http.protocol.BasicHttpContext; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +@SuppressWarnings("deprecation") +class TestHttpClientContext { + + @Test + void testDeprecatedSetAttributes() { + final HttpClientContext context1 = HttpClientContext.cast(new BasicHttpContext()); + context1.setAttribute(HttpClientContext.USER_TOKEN, "blah"); + Assertions.assertEquals("blah", context1.getUserToken()); + + final HttpClientContext context2 = HttpClientContext.create(); + context2.setAttribute(HttpClientContext.USER_TOKEN, "blah"); + Assertions.assertEquals("blah", context2.getUserToken()); + } + +} diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestMainClientExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestMainClientExec.java index aa58ff126..7dea493c0 100644 --- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestMainClientExec.java +++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestMainClientExec.java @@ -344,4 +344,48 @@ void testExecIOException() throws Exception { Mockito.verify(execRuntime).discardEndpoint(); } + @Test + void testGetUserTokenNewWay() { + // Set user token using the new method + final HttpClientContext context = HttpClientContext.create(); + final String expectedToken = "nwe token way"; + context.setUserToken(expectedToken); + + // Retrieve using the getter + final Object actualToken = context.getUserToken(); + + // Validate that the token is set and retrieved correctly + Assertions.assertEquals(expectedToken, actualToken, "The user token should match the one set by setUserToken()."); + } + + @Test + void testGetUserTokenOldWay() { + // Set user token using context attributes (old way) + final HttpClientContext context = HttpClientContext.create(); + final String expectedToken = "old token way"; + context.setAttribute(HttpClientContext.USER_TOKEN, expectedToken); + + // Retrieve using the getter + final Object actualToken = context.getUserToken(); + + // Validate that the token is retrieved correctly for backward compatibility + Assertions.assertEquals(expectedToken, actualToken, "The user token should match the one set by context attribute for backward compatibility."); + } + + @Test + void testGetUserTokenBothSet() { + // Set user token using both the new and old methods + final HttpClientContext context = HttpClientContext.create(); + final String newToken = "new token way"; + final String oldToken = "old token way"; + context.setUserToken(newToken); + context.setAttribute(HttpClientContext.USER_TOKEN, oldToken); + + // Retrieve using the getter + final Object actualToken = context.getUserToken(); + + // Validate that the new method takes precedence over the old one + Assertions.assertEquals(newToken, actualToken, "The user token should match the one set by setUserToken(), taking precedence over the context attribute."); + } + }