Skip to content

Commit f19962d

Browse files
committed
refactor(interceptors): add post_marshal interception point for thread-local cleanup
- Added ExtendedServerRequestInterceptor.post_marshal() method to clean up thread-local state after response marshalling - Added default implementations for all ExtendedServerRequestInterceptor methods to reduce boilerplate - Updated PIManager.serverPostMarshal() to invoke post_marshal on extended interceptors - Modified PIUpcall.postMarshal() to call piManager_.serverPostMarshal() before super.postMarshal() - Updated ServerRequestInfo_impl._OB_postMarshal() to call post_marshal on extended interceptors with CMSF/YASF override context - Refactored YasfServerInterceptor to use post_marshal for cleanup instead of send_reply/send_exception/send_other - Refactored RoflServerInterceptor to use post_marshal for cleanup instead of send_reply/send_exception/send_other - Refactored CmsfServerInterceptor to use post_marshal for cleanup instead of setupCmsfThreadLocalValue in send methods - Modernized ThreadLocal initialization in CmsfThreadLocal and YasfThreadLocal to use withInitial() - Fixed YasfTest.Echo interface visibility to public - Substantive lines added: 152, lines removed: 65 This fixes the YasfTest failure where YASF thread-local state was not properly available during serialization. The new post_marshal interception point ensures thread-local state is cleaned up after marshalling completes, matching the lifecycle established by pre_unmarshal for setup after context switches. Co-authored-by-AI: IBM Bob 1.0.4
1 parent 70f978f commit f19962d

10 files changed

Lines changed: 154 additions & 67 deletions

File tree

yoko-core/src/main/java/org/apache/yoko/orb/OB/PIManager.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,12 @@ void serverContextSwitch(ServerRequestInfo info) {
219219
impl._OB_contextSwitch();
220220
}
221221

222+
// Call post_marshal on extended interceptors after response marshalling
223+
void serverPostMarshal(ServerRequestInfo info) {
224+
ServerRequestInfo_impl impl = (ServerRequestInfo_impl) info;
225+
impl._OB_postMarshal();
226+
}
227+
222228
// Set the parameter information (SSI case)
223229
void serverParameterDesc(ServerRequestInfo info, ParameterDesc[] argDesc, ParameterDesc retDesc, TypeCode[] exceptionTC) {
224230
ServerRequestInfo_impl impl = (ServerRequestInfo_impl) info;

yoko-core/src/main/java/org/apache/yoko/orb/OB/PIUpcall.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,11 @@ public YokoOutputStream preMarshal() throws LocationForward {
8282
return super.preMarshal();
8383
}
8484

85+
public void postMarshal() {
86+
piManager_.serverPostMarshal(requestInfo_);
87+
super.postMarshal();
88+
}
89+
8590
public void setUserException(Any any) {
8691
try {
8792
UnknownUserException uex = new UnknownUserException(any);
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2026 IBM Corporation and others.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*
16+
* SPDX-License-Identifier: Apache-2.0
17+
*/
18+
package org.apache.yoko.orb.PortableInterceptor;
19+
20+
import org.omg.PortableInterceptor.ForwardRequest;
21+
import org.omg.PortableInterceptor.ServerRequestInfo;
22+
import org.omg.PortableInterceptor.ServerRequestInterceptor;
23+
24+
/**
25+
* Extended server request interceptor interface that provides additional
26+
* interception points for setting up thread-local state after a context switch
27+
* and cleaning up after marshalling.
28+
* This is needed when the request processing switches to a different thread
29+
* between receive_request_service_contexts and argument deserialization,
30+
* and when thread-local state needs to be cleaned up after response marshalling.
31+
*
32+
* All methods have default empty implementations to simplify implementation.
33+
*/
34+
public interface ExtendedServerRequestInterceptor extends ServerRequestInterceptor {
35+
/**
36+
* Called after a context switch to set up thread-local state on the new thread.
37+
* This is invoked before argument deserialization begins, allowing interceptors
38+
* to retrieve data from PICurrent slots and push it onto thread locals.
39+
*
40+
* @param ri the server request info
41+
*/
42+
default void pre_unmarshal(ServerRequestInfo ri) {}
43+
44+
/**
45+
* Called after response marshalling is complete to clean up thread-local state.
46+
* This is invoked after the response has been marshalled, allowing interceptors
47+
* to clean up any thread-local state that was set up during request processing.
48+
*
49+
* @param ri the server request info
50+
*/
51+
default void post_marshal(ServerRequestInfo ri) {}
52+
53+
@Override
54+
default void receive_request_service_contexts(ServerRequestInfo ri) throws ForwardRequest {}
55+
56+
@Override
57+
default void receive_request(ServerRequestInfo ri) throws ForwardRequest {}
58+
59+
@Override
60+
default void send_reply(ServerRequestInfo ri) {}
61+
62+
@Override
63+
default void send_exception(ServerRequestInfo ri) throws ForwardRequest {}
64+
65+
@Override
66+
default void send_other(ServerRequestInfo ri) throws ForwardRequest {}
67+
68+
@Override
69+
default void destroy() {}
70+
}

yoko-core/src/main/java/org/apache/yoko/orb/PortableInterceptor/ServerRequestInfo_impl.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ public void _OB_requestServiceContext(List<ServerRequestInterceptor> interceptor
291291
Delegate p = (Delegate) (((ObjectImpl) ex.forward)._get_delegate());
292292
throw new LocationForward(p._OB_IOR(), false);
293293
}
294+
// Note: CMSF/YASF/ROFL data pushed by interceptors during receive_request_service_contexts
295+
// is now active (override has closed) and will be available during argument deserialization
294296
}
295297

296298
public void _OB_request() throws LocationForward {
@@ -411,6 +413,28 @@ public void _OB_contextSwitch() {
411413
logger.fine(() -> "Pushing the PICurrent because of a context switch");
412414
currentNeedsPopping = true;
413415
piCurrent._OB_pushSlotData(requestSlotData);
416+
// Call pre_unmarshal on extended interceptors after context switch
417+
// Use override to maintain consistency with other interceptor calls
418+
try (CmsfOverride ignored = CmsfThreadLocal.override();
419+
YasfOverride ignored1 = YasfThreadLocal.override()) {
420+
interceptors.stream()
421+
.filter(ExtendedServerRequestInterceptor.class::isInstance)
422+
.map(ExtendedServerRequestInterceptor.class::cast)
423+
.forEach(i -> i.pre_unmarshal(this));
424+
}
425+
}
426+
}
427+
428+
// Called after response marshalling to clean up thread-local state
429+
public void _OB_postMarshal() {
430+
logger.fine(() -> "Calling post_marshal on extended interceptors");
431+
// Use override to maintain consistency with other interceptor calls
432+
try (CmsfOverride ignored = CmsfThreadLocal.override();
433+
YasfOverride ignored1 = YasfThreadLocal.override()) {
434+
interceptors.stream()
435+
.filter(ExtendedServerRequestInterceptor.class::isInstance)
436+
.map(ExtendedServerRequestInterceptor.class::cast)
437+
.forEach(i -> i.post_marshal(this));
414438
}
415439
}
416440

yoko-core/src/main/java/org/apache/yoko/orb/cmsf/CmsfServerInterceptor.java

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818
package org.apache.yoko.orb.cmsf;
1919

20+
import org.apache.yoko.orb.PortableInterceptor.ExtendedServerRequestInterceptor;
2021
import org.apache.yoko.util.cmsf.CmsfThreadLocal;
2122
import org.omg.CORBA.BAD_PARAM;
2223
import org.omg.CORBA.INTERNAL;
@@ -26,7 +27,6 @@
2627
import org.omg.PortableInterceptor.ForwardRequest;
2728
import org.omg.PortableInterceptor.InvalidSlot;
2829
import org.omg.PortableInterceptor.ServerRequestInfo;
29-
import org.omg.PortableInterceptor.ServerRequestInterceptor;
3030

3131
import java.io.IOException;
3232
import java.io.NotSerializableException;
@@ -38,12 +38,12 @@
3838
import static org.apache.yoko.util.Hex.formatHexPara;
3939
import static org.apache.yoko.util.MinorCodes.MinorInvalidServiceContextId;
4040

41-
public final class CmsfServerInterceptor extends LocalObject implements ServerRequestInterceptor {
41+
public final class CmsfServerInterceptor extends LocalObject implements ExtendedServerRequestInterceptor {
4242
private static final Logger LOGGER = Logger.getLogger(CmsfServerInterceptor.class.getName());
4343
private static final String NAME = CmsfServerInterceptor.class.getName();
4444

4545
private final int slotId;
46-
46+
4747
public CmsfServerInterceptor(int slotId) {
4848
this.slotId = slotId;
4949
}
@@ -60,6 +60,7 @@ public void receive_request_service_contexts(ServerRequestInfo ri) throws Forwar
6060
} catch (BAD_PARAM e) {
6161
if (e.minor != MinorInvalidServiceContextId) throw e;
6262
}
63+
// Store in slot - will be retrieved after context switch in pre_unmarshal
6364
try {
6465
ri.set_slot(slotId, cmsf.getAny());
6566
} catch (InvalidSlot e) {
@@ -68,47 +69,31 @@ public void receive_request_service_contexts(ServerRequestInfo ri) throws Forwar
6869
}
6970

7071
@Override
71-
public void receive_request(ServerRequestInfo ri) throws ForwardRequest {
72-
}
73-
74-
private void setupCmsfThreadLocalValue(ServerRequestInfo ri) {
75-
CmsfVersion cmsf = CMSFv1;
72+
public void pre_unmarshal(ServerRequestInfo ri) {
73+
// Push CMSF data after context switch, before argument deserialization
7674
try {
77-
cmsf = CmsfVersion.readAny(ri.get_slot(slotId));
75+
CmsfVersion cmsf = CmsfVersion.readAny(ri.get_slot(slotId));
76+
CmsfThreadLocal.push(cmsf.getValue());
7877
} catch (InvalidSlot e) {
7978
throw (INTERNAL)(new INTERNAL(e.getMessage())).initCause(e);
8079
}
81-
CmsfThreadLocal.push(cmsf.getValue());
82-
}
83-
84-
@Override
85-
public void send_reply(ServerRequestInfo ri) {
86-
setupCmsfThreadLocalValue(ri);
8780
}
8881

8982
@Override
90-
public void send_exception(ServerRequestInfo ri) throws ForwardRequest {
91-
setupCmsfThreadLocalValue(ri);
92-
}
93-
94-
@Override
95-
public void send_other(ServerRequestInfo ri) throws ForwardRequest {
96-
setupCmsfThreadLocalValue(ri);
83+
public void post_marshal(ServerRequestInfo ri) {
84+
// Pop CMSF data after marshalling is complete
85+
CmsfThreadLocal.pop();
9786
}
9887

9988
@Override
10089
public String name() {
10190
return NAME;
10291
}
10392

104-
@Override
105-
public void destroy() {
106-
}
107-
10893
private void readObject(ObjectInputStream ios) throws IOException {
10994
throw new NotSerializableException(NAME);
11095
}
111-
96+
11297
private void writeObject(ObjectOutputStream oos) throws IOException {
11398
throw new NotSerializableException(NAME);
11499
}

yoko-core/src/main/java/org/apache/yoko/orb/rofl/RoflServerInterceptor.java

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2025 IBM Corporation and others.
2+
* Copyright 2026 IBM Corporation and others.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,14 +17,14 @@
1717
*/
1818
package org.apache.yoko.orb.rofl;
1919

20+
import org.apache.yoko.orb.PortableInterceptor.ExtendedServerRequestInterceptor;
2021
import org.apache.yoko.util.rofl.RoflHelper;
2122
import org.apache.yoko.util.rofl.RoflThreadLocal;
2223
import org.omg.CORBA.LocalObject;
2324
import org.omg.PortableInterceptor.ForwardRequest;
2425
import org.omg.PortableInterceptor.ServerRequestInfo;
25-
import org.omg.PortableInterceptor.ServerRequestInterceptor;
2626

27-
public class RoflServerInterceptor extends LocalObject implements ServerRequestInterceptor {
27+
public class RoflServerInterceptor extends LocalObject implements ExtendedServerRequestInterceptor {
2828
private static final String NAME = RoflServerInterceptor.class.getName();
2929
private final RoflHelper roflHelper;
3030

@@ -33,13 +33,19 @@ public RoflServerInterceptor(int slotId) {
3333
}
3434
public void receive_request_service_contexts(ServerRequestInfo ri) throws ForwardRequest {
3535
RoflThreadLocal.reset();
36+
// Store in slot - will be retrieved after context switch in pre_unmarshal
3637
roflHelper.findAndSave(ri);
3738
}
3839

39-
public void receive_request(ServerRequestInfo ri) {}
40-
public void send_reply(ServerRequestInfo ri) { RoflThreadLocal.push(roflHelper.loadAndCreate(ri)); }
41-
public void send_exception(ServerRequestInfo ri) { RoflThreadLocal.push(roflHelper.loadAndCreate(ri)); }
42-
public void send_other(ServerRequestInfo ri) { RoflThreadLocal.push(roflHelper.loadAndCreate(ri)); }
40+
public void pre_unmarshal(ServerRequestInfo ri) {
41+
// Push ROFL data after context switch, before argument deserialization
42+
RoflThreadLocal.push(roflHelper.loadAndCreate(ri));
43+
}
44+
45+
public void post_marshal(ServerRequestInfo ri) {
46+
// Pop ROFL data after marshalling is complete
47+
RoflThreadLocal.pop();
48+
}
49+
4350
public String name() { return NAME; }
44-
public void destroy() {}
4551
}

yoko-core/src/main/java/org/apache/yoko/orb/yasf/YasfServerInterceptor.java

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 IBM Corporation and others.
2+
* Copyright 2026 IBM Corporation and others.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,19 +17,19 @@
1717
*/
1818
package org.apache.yoko.orb.yasf;
1919

20-
import java.io.IOException;
21-
import java.io.NotSerializableException;
22-
import java.io.ObjectInputStream;
23-
import java.io.ObjectOutputStream;
24-
20+
import org.apache.yoko.orb.PortableInterceptor.ExtendedServerRequestInterceptor;
2521
import org.apache.yoko.util.yasf.Yasf;
2622
import org.apache.yoko.util.yasf.YasfThreadLocal;
2723
import org.omg.CORBA.LocalObject;
2824
import org.omg.PortableInterceptor.ForwardRequest;
2925
import org.omg.PortableInterceptor.ServerRequestInfo;
30-
import org.omg.PortableInterceptor.ServerRequestInterceptor;
3126

32-
public class YasfServerInterceptor extends LocalObject implements ServerRequestInterceptor {
27+
import java.io.IOException;
28+
import java.io.NotSerializableException;
29+
import java.io.ObjectInputStream;
30+
import java.io.ObjectOutputStream;
31+
32+
public class YasfServerInterceptor extends LocalObject implements ExtendedServerRequestInterceptor {
3333
private static final String NAME = YasfServerInterceptor.class.getName();
3434

3535
private final int slotId;
@@ -42,31 +42,34 @@ public YasfServerInterceptor(int slotId) {
4242
public void receive_request_service_contexts(ServerRequestInfo ri) throws ForwardRequest {
4343
YasfThreadLocal.reset();
4444
byte[] yasfData = YasfHelper.readData(ri);
45+
// Store in slot - will be retrieved after context switch in pre_unmarshal
4546
YasfHelper.setSlot(slotId, ri, yasfData);
4647
}
4748

4849
@Override
49-
public void receive_request(ServerRequestInfo ri) throws ForwardRequest {
50+
public void pre_unmarshal(ServerRequestInfo ri) {
51+
// Push YASF data after context switch, before argument deserialization
52+
YasfThreadLocal.push(Yasf.toSet(YasfHelper.getSlot(slotId, ri)));
53+
}
54+
55+
@Override
56+
public void post_marshal(ServerRequestInfo ri) {
57+
// Pop YASF data after marshalling is complete
58+
YasfThreadLocal.pop();
5059
}
5160

5261
@Override
5362
public void send_reply(ServerRequestInfo ri) {
54-
YasfThreadLocal.push(Yasf.toSet(YasfHelper.getSlot(slotId, ri)));
55-
// Adding for diagnostic purposes
5663
YasfHelper.addSc(ri);
5764
}
5865

5966
@Override
60-
public void send_exception(ServerRequestInfo ri) throws ForwardRequest {
61-
YasfThreadLocal.push(Yasf.toSet(YasfHelper.getSlot(slotId, ri)));
62-
// Adding for diagnostic purposes
67+
public void send_exception(ServerRequestInfo ri) {
6368
YasfHelper.addSc(ri);
6469
}
6570

6671
@Override
67-
public void send_other(ServerRequestInfo ri) throws ForwardRequest {
68-
YasfThreadLocal.push(Yasf.toSet(YasfHelper.getSlot(slotId, ri)));
69-
// Adding for diagnostic purposes
72+
public void send_other(ServerRequestInfo ri) {
7073
YasfHelper.addSc(ri);
7174
}
7275

@@ -75,10 +78,6 @@ public String name() {
7578
return NAME;
7679
}
7780

78-
@Override
79-
public void destroy() {
80-
}
81-
8281
private void readObject(ObjectInputStream ios) throws IOException {
8382
throw new NotSerializableException(NAME);
8483
}

yoko-util/src/main/java/org/apache/yoko/util/cmsf/CmsfThreadLocal.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@
2626
*/
2727
public final class CmsfThreadLocal {
2828
private static final Logger LOGGER = Logger.getLogger(CmsfThreadLocal.class.getName());
29-
private static final ThreadLocal<CmsfInfo> cmsfInfo = new ThreadLocal<CmsfInfo>() {
30-
@Override protected CmsfInfo initialValue() {
31-
return new CmsfInfo();
32-
}
33-
};
29+
private static final ThreadLocal<CmsfInfo> cmsfInfo = ThreadLocal.withInitial(CmsfInfo::new);
3430

3531
private CmsfThreadLocal() {}
3632

yoko-util/src/main/java/org/apache/yoko/util/yasf/YasfThreadLocal.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,7 @@
2525
*/
2626
public final class YasfThreadLocal {
2727
private static final Logger LOGGER = Logger.getLogger(YasfThreadLocal.class.getName());
28-
private static final ThreadLocal<YasfInfo> yasfInfo = new ThreadLocal<YasfInfo>() {
29-
@Override protected YasfInfo initialValue() {
30-
return new YasfInfo();
31-
}
32-
};
28+
private static final ThreadLocal<YasfInfo> yasfInfo = ThreadLocal.withInitial(YasfInfo::new);
3329

3430
private YasfThreadLocal() {}
3531

0 commit comments

Comments
 (0)