Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 31 additions & 10 deletions core/src/main/java/org/apache/cxf/endpoint/ClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,7 @@
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.logging.Level;
Expand Down Expand Up @@ -107,6 +100,35 @@ public class ClientImpl
protected Map<Thread, ResponseContext> responseContext
= Collections.synchronizedMap(new WeakHashMap<Thread, ResponseContext>());

/**
* Set of properties that should not be propagated into the ResponseContext from IN Message
*/
private static final Set<String> RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES = new HashSet<>(
List.of(
// remove the recursive reference if present
Message.INVOCATION_CONTEXT
)
);

/**
* Method that a cxf submodule can call to add a property not to propagate from IN Message into the ResponseContext
* @param property to exclude
*/
public static void addResponseContextExcludedInProperty(String property) {
RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES.add(property);
}
public static void addAllResponseContextExcludedInProperties(Set<String> properties) {
RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES.addAll(properties);
}

/**
* Method to remove RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES from ResponseContext Map
* @param context ResponseContext Map
*/
protected void filterResponseContextProperties(Map<String, Object> context) {
RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES.forEach(context::remove);
}

protected Executor executor;

public ClientImpl(Bus b, Endpoint e) {
Expand Down Expand Up @@ -648,8 +670,7 @@ protected Object[] processResult(Message message,
if (inMsg != null) {
if (null != resContext) {
resContext.putAll(inMsg);
// remove the recursive reference if present
resContext.remove(Message.INVOCATION_CONTEXT);
filterResponseContextProperties(resContext);
setResponseContext(resContext);
}
resList = CastUtils.cast(inMsg.getContent(List.class));
Expand Down
124 changes: 124 additions & 0 deletions core/src/test/java/org/apache/cxf/endpoint/ClientImplTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.apache.cxf.endpoint;


import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.cxf.BusFactory;
import org.apache.cxf.message.Message;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import static org.junit.Assert.*;

public class ClientImplTest {

private static class TestClientImpl extends ClientImpl {

public TestClientImpl() {
super(BusFactory.newInstance().createBus(), null);
}

void filter(Map<String, Object> context) {
filterResponseContextProperties(context);
}
}

private final TestClientImpl testClientImpl = new TestClientImpl();

private static Set<String> getExcludedProperties() throws Exception {
Field field = ClientImpl.class
.getDeclaredField("RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES");

field.setAccessible(true);

@SuppressWarnings("unchecked")
Set<String> properties = (Set<String>) field.get(null);

return properties;
}

private static Set<String> defaultExcludedProperties;

@BeforeClass
public static void initDefaults() throws Exception {
defaultExcludedProperties =
new HashSet<>(getExcludedProperties());
}

@Before
public void setUp() throws Exception {
Set<String> properties = getExcludedProperties();

properties.clear();
properties.addAll(defaultExcludedProperties);
}

@Test
public void shouldFilterDefaultExcludedProperty() {

Map<String, Object> context = new HashMap<>();
context.put(Message.INVOCATION_CONTEXT, "invocation-context");
context.put("property.to.keep", "value");

testClientImpl.filter(context);

assertFalse(context.containsKey(Message.INVOCATION_CONTEXT));
assertEquals("value", context.get("property.to.keep"));
}

@Test
public void shouldFilterPropertyAddedWithAdd() {
String property = "my.custom.property";

ClientImpl.addResponseContextExcludedInProperty(property);

Map<String, Object> context = new HashMap<>();
context.put(property, "custom-value");
context.put("property.to.keep", "value");

testClientImpl.filter(context);

assertFalse(context.containsKey(property));
assertEquals("value", context.get("property.to.keep"));
}

@Test
public void shouldFilterPropertiesAddedWithAddAll() {
Set<String> properties = Set.of(
"custom.property.1",
"custom.property.2"
);

ClientImpl.addAllResponseContextExcludedInProperties(properties);

Map<String, Object> context = new HashMap<>();
context.put("custom.property.1", "value1");
context.put("custom.property.2", "value2");
context.put("property.to.keep", "keep");

testClientImpl.filter(context);

assertFalse(context.containsKey("custom.property.1"));
assertFalse(context.containsKey("custom.property.2"));
assertEquals("keep", context.get("property.to.keep"));
}

@Test
public void shouldKeepPropertiesNotExcluded() {

Map<String, Object> context = new HashMap<>();
context.put("property.1", "value1");
context.put("property.2", "value2");

testClientImpl.filter(context);

assertEquals(2, context.size());
assertEquals("value1", context.get("property.1"));
assertEquals("value2", context.get("property.2"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
import org.apache.cxf.phase.Phase;
import org.apache.cxf.phase.PhaseInterceptor;

import static org.apache.cxf.endpoint.ClientImpl.addResponseContextExcludedInProperty;

/**
*
*/
Expand Down Expand Up @@ -71,6 +73,9 @@ public LoggingInInterceptor(PrintWriter writer) {

public LoggingInInterceptor(LogEventSender sender) {
super(Phase.PRE_INVOKE, sender);

//Make sure that the LIVE_LOGGING_PROP won't be propagated into the ResponseContext from IN Messages
addResponseContextExcludedInProperty(LIVE_LOGGING_PROP);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vp340 thanks for another alternative, the problem I see with this one is two fold: LoggingXxxInteceptor has to be aware about the ClientImpl specifics/internals but this is generic feature that works for client (we have many) or/and server (same, many).

}

public Collection<PhaseInterceptor<? extends Message>> getAdditionalInterceptors() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Collections;
Expand All @@ -29,6 +30,7 @@
import java.util.Map;
import java.util.Set;

import org.apache.cxf.endpoint.ClientImpl;
import org.apache.cxf.ext.logging.event.LogEvent;
import org.apache.cxf.io.CachedOutputStream;
import org.apache.cxf.message.ExchangeImpl;
Expand All @@ -38,11 +40,13 @@
import org.junit.Before;
import org.junit.Test;

import static org.apache.cxf.ext.logging.AbstractLoggingInterceptor.LIVE_LOGGING_PROP;
import static org.apache.cxf.ext.logging.event.DefaultLogEventMapper.MASKED_HEADER_VALUE;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

public class LoggingInInterceptorTest {
private static final String TEST_HEADER_VALUE = "TestValue";
Expand Down Expand Up @@ -234,4 +238,17 @@ public void shouldLogMultipartPayloadNoHeaders() throws IOException {

assertThat(event.getPayload(), equalToIgnoringCase(buf.toString()));
}

@Test
public void shouldAddResponseContextInExcludedProperty() throws NoSuchFieldException, IllegalAccessException {
Field field = ClientImpl.class
.getDeclaredField("RESPONSE_CONTEXT_EXCLUDED_IN_PROPERTIES");

field.setAccessible(true);

@SuppressWarnings("unchecked")
Set<String> actual = (Set<String>) field.get(null);

assertTrue(actual.contains(LIVE_LOGGING_PROP));
}
}