Skip to content

Commit f4bf46e

Browse files
committed
Merge remote-tracking branch 'origin/fat-tests-36500-cache-name-prefix' into fix-prefix-java2sec-remove-listener
2 parents 772bcaf + 11879dc commit f4bf46e

28 files changed

Lines changed: 1506 additions & 8 deletions

File tree

dev/com.ibm.ws.session.cache/resources/OSGI-INF/l10n/metatype.properties

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
###############################################################################
2-
# Copyright (c) 2018, 2023 IBM Corporation and others.
2+
# Copyright (c) 2018, 2026 IBM Corporation and others.
33
# All rights reserved. This program and the accompanying materials
44
# are made available under the terms of the Eclipse Public License 2.0
55
# which accompanies this distribution, and is available at
@@ -30,7 +30,10 @@ cacheSeparator=Cache name separator
3030
cacheSeparator.desc=The single character used to separate the session meta cache name. The default value should usually be used.
3131

3232
appInCacheName=Use the application name in the cache names
33-
appInCacheName.desc=By default, per-application JCache session cache names are generated by using the context root. When the JCache session caches are distributed across multiple servers, multiple applications with the same context root might exist that must not share a session cache. When this option is enabled, application names are included in JCache cache names to help avoid conflicting JCache cache names. The default value is false.
33+
appInCacheName.desc=By default, JCache session cache names are generated using the application context root. In distributed environments with multiple servers, this can cause conflicts when different applications share the same context root but require separate session caches. Enabling this option appends the application name to the JCache cache name, preventing such conflicts. The default value is false.
34+
35+
cacheNamePrefix=Cache name prefix
36+
cacheNamePrefix.desc=An optional prefix for Liberty-generated cache names, useful for preventing conflicts when multiple Liberty instances share the same cache store. If not specified, the prefix defaults to the standard com.ibm.ws.session value.
3437

3538
properties=JCache Configuration Properties
3639
properties.desc=List of vendor-specific JCache configuration properties, which are passed to the JCache provider when the CacheManager is obtained. This setting is ignored when cacheManagerRef is used.

dev/com.ibm.ws.session.cache/resources/OSGI-INF/metatype/metatype.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
</AD>
4343
<AD id="writeInterval" type="String" ibm:type="duration(s)" default="2m" ibmui:group="performance" name="%writeInterval" description="%writeInterval.desc"/>
4444
<AD id="cacheSeparator" type="String" required="false" default="%" ibmui:group="performance" name="%cacheSeparator" description="%cacheSeparator.desc"/>
45+
<AD id="cacheNamePrefix" type="String" required="false" default="" ibmui:group="performance" name="%cacheNamePrefix" description="%cacheNamePrefix.desc"/>
4546
<AD id="appInCacheName" type="Boolean" required="false" default="false" ibmui:group="performance" name="%appInCacheName" description="%appInCacheName.desc"/>
4647

4748
<!--

dev/com.ibm.ws.session.cache/src/com/ibm/ws/session/store/cache/CacheHashMap.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018, 2024 IBM Corporation and others.
2+
* Copyright (c) 2018, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -78,6 +78,12 @@ public class CacheHashMap extends BackedHashMap {
7878
*/
7979
private static final Pattern COLON = Pattern.compile(":"), PERCENT = Pattern.compile("%"), SLASH = Pattern.compile("/");
8080

81+
/**
82+
* Cache name prefixes for session metadata and attributes
83+
*/
84+
private static final String SESSION_META_CACHE_PREFIX = "com.ibm.ws.session.meta.";
85+
private static final String SESSION_ATTR_CACHE_PREFIX = "com.ibm.ws.session.attr.";
86+
8187
/**
8288
* The end-of-line marker.
8389
*/
@@ -169,7 +175,9 @@ private void cacheInit() {
169175

170176
// Session Meta Information Cache
171177

172-
String metaCacheName = new StringBuilder(24 + a.length()).append("com.ibm.ws.session.meta.").append(a).toString();
178+
String prefix = cacheStoreService.cacheNamePrefix;
179+
String baseMetaPrefix = prefix.isEmpty() ? SESSION_META_CACHE_PREFIX : prefix + SESSION_META_CACHE_PREFIX;
180+
String metaCacheName = new StringBuilder(baseMetaPrefix.length() + a.length()).append(baseMetaPrefix).append(a).toString();
173181

174182
if (trace && tc.isDebugEnabled())
175183
tcInvoke(cacheStoreService.tcCacheManager, "getCache", metaCacheName, "String", "ArrayList");
@@ -209,7 +217,8 @@ private void cacheInit() {
209217

210218
// Session Attributes Cache
211219

212-
String attrCacheName = new StringBuilder(24 + a.length()).append("com.ibm.ws.session.attr.").append(a).toString();
220+
String baseAttrPrefix = prefix.isEmpty() ? SESSION_ATTR_CACHE_PREFIX : prefix + SESSION_ATTR_CACHE_PREFIX;
221+
String attrCacheName = new StringBuilder(baseAttrPrefix.length() + a.length()).append(baseAttrPrefix).append(a).toString();
213222

214223
if (trace && tc.isDebugEnabled())
215224
tcInvoke(cacheStoreService.tcCacheManager, "getCache", attrCacheName, "String", "byte[]");

dev/com.ibm.ws.session.cache/src/com/ibm/ws/session/store/cache/CacheStoreService.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018, 2022 IBM Corporation and others.
2+
* Copyright (c) 2018, 2026 IBM Corporation and others.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License 2.0
55
* which accompanies this distribution, and is available at
@@ -82,6 +82,7 @@ public class CacheStoreService implements Introspector, SessionStoreService {
8282
private static final String CONFIG_KEY_PROPERTIES = "properties";
8383
private static final Set<String> sessionCacheAttributes = new HashSet<>(Arrays.asList("appInCacheName",
8484
"cacheSeparator",
85+
"cacheNamePrefix",
8586
"scheduleInvalidationFirstHour",
8687
"scheduleInvalidationSecondHour",
8788
"writeContents",
@@ -103,6 +104,12 @@ public class CacheStoreService implements Introspector, SessionStoreService {
103104

104105
final AtomicReference<ServiceReference<?>> monitorRef = new AtomicReference<ServiceReference<?>>();
105106

107+
108+
/**
109+
* Optional prefix to prepend to Liberty-generated cache names.
110+
* Empty string means no prefix (default behavior for backward compatibility).
111+
*/
112+
volatile String cacheNamePrefix = "";
106113
SerializationService serializationService;
107114
private CacheManagerService cacheManagerService;
108115

@@ -145,6 +152,8 @@ private void processConfiguration(Map<String, Object> props) {
145152
Object scheduleInvalidationFirstHour = configurationProperties.get("scheduleInvalidationFirstHour");
146153
Object scheduleInvalidationSecondHour = configurationProperties.get("scheduleInvalidationSecondHour");
147154
Object writeContents = configurationProperties.get("writeContents");
155+
Object prefix = configurationProperties.get("cacheNamePrefix");
156+
cacheNamePrefix = (prefix instanceof String) ? (String) prefix : "";
148157
Object writeFrequency = configurationProperties.get("writeFrequency");
149158

150159
// httpSessionCache writeContents accepts ONLY_SET_ATTRIBUTES in place of ONLY_UPDATED_ATTRIBUTES to better reflect the behavior provided
@@ -482,8 +491,8 @@ public void introspect(PrintWriter out) throws Exception {
482491
// detailed information per cache
483492
for (String cacheName : cacheNames) {
484493
out.println();
485-
boolean isMetaCache = cacheName.startsWith("com.ibm.ws.session.meta.");
486-
boolean isAttrCache = cacheName.startsWith("com.ibm.ws.session.attr.");
494+
boolean isMetaCache = cacheName.contains("com.ibm.ws.session.meta.");
495+
boolean isAttrCache = cacheName.contains("com.ibm.ws.session.attr.");
487496
out.println("Cache " + cacheName + ":");
488497
Cache<?, ?> cache = isMetaCache ? cacheManager.getCache(cacheName, String.class, ArrayList.class)
489498
: isAttrCache ? cacheManager.getCache(cacheName, String.class, byte[].class)

dev/com.ibm.ws.session.cache_fat/fat/src/com/ibm/ws/session/cache/fat/FATSuite.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
SessionCacheTwoServerTest.class,
3838
SessionCacheTimeoutTest.class,
3939
SessionCacheTwoServerTimeoutTest.class,
40+
SessionCachePrefixTest.class,
4041
HazelcastClientTest.class
4142
})
4243

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
/*******************************************************************************
2+
* Copyright (c) 2026 IBM Corporation and others.
3+
* All rights reserved. This program and the accompanying materials
4+
* are made available under the terms of the Eclipse Public License 2.0
5+
* which accompanies this distribution, and is available at
6+
* http://www.eclipse.org/legal/epl-2.0/
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*
10+
* Contributors:
11+
* IBM Corporation - initial API and implementation
12+
*******************************************************************************/
13+
package com.ibm.ws.session.cache.fat;
14+
15+
import static org.junit.Assert.assertNotNull;
16+
17+
import java.io.File;
18+
import java.util.ArrayList;
19+
import java.util.Arrays;
20+
import java.util.List;
21+
import java.util.UUID;
22+
23+
import org.junit.AfterClass;
24+
import org.junit.BeforeClass;
25+
import org.junit.ClassRule;
26+
import org.junit.Test;
27+
import org.junit.runner.RunWith;
28+
29+
import com.ibm.websphere.simplicity.log.Log;
30+
31+
import componenttest.annotation.Server;
32+
import componenttest.custom.junit.runner.FATRunner;
33+
import componenttest.custom.junit.runner.RepeatTestFilter;
34+
import componenttest.rules.repeater.RepeatTests;
35+
import componenttest.topology.impl.LibertyServer;
36+
import componenttest.topology.utils.FATServletClient;
37+
38+
/**
39+
* Tests for cacheNamePrefix configuration with Hazelcast.
40+
* This feature allows customers to customize session cache names when multiple
41+
* Liberty instances share the same Hazelcast cluster.
42+
*
43+
* Uses a single server instance with setServerConfigurationFile() to test
44+
* different prefix configurations sequentially.
45+
*/
46+
@RunWith(FATRunner.class)
47+
public class SessionCachePrefixTest extends FATServletClient {
48+
49+
@Server("sessionCachePrefixServer")
50+
public static LibertyServer server;
51+
52+
public static SessionCacheApp app = null;
53+
54+
@ClassRule
55+
public static RepeatTests repeatRule = RepeatTests.withoutModification().andWith(new CacheManagerRepeatAction());
56+
57+
@BeforeClass
58+
public static void setUp() throws Exception {
59+
app = new SessionCacheApp(server, true, "session.cache.web", "session.cache.web.listener1");
60+
61+
String hazelcastConfigFile = "hazelcast-localhost-only-multicastDisabled.xml";
62+
String configLocation = new File(server.getUserDir() + "/shared/resources/hazelcast/" + hazelcastConfigFile).getAbsolutePath();
63+
64+
List<String> jvmOptions = Arrays.asList("-Dhazelcast.group.name=" + UUID.randomUUID(),
65+
"-Dhazelcast.config=" + configLocation);
66+
67+
server.setJvmOptions(jvmOptions);
68+
}
69+
70+
@AfterClass
71+
public static void tearDown() throws Exception {
72+
if (server != null && server.isStarted()) {
73+
server.stopServer("CWWKG0058E", "CWWKO0221E");
74+
}
75+
}
76+
77+
/**
78+
* Test Scenario 1: Custom prefix configured
79+
* Verify that cache names use the custom prefix "testPrefix_" when configured.
80+
*/
81+
@Test
82+
public void testCustomPrefix() throws Exception {
83+
server.setServerConfigurationFile("server_customPrefix.xml");
84+
server.startServer();
85+
86+
try {
87+
List<String> session = new ArrayList<>();
88+
String sessionId = app.sessionPut("testKey", "testValue", session, true);
89+
assertNotNull("Session ID should not be null", sessionId);
90+
91+
// Verify session data can be retrieved
92+
app.sessionGet("testKey", "testValue", session);
93+
94+
// Check logs for custom prefix "testPrefix_"
95+
assertNotNull("Should find custom prefix in cache names",
96+
server.waitForStringInTrace("testPrefix_com\\.ibm\\.ws\\.session\\.(attr|meta)", 30000));
97+
98+
Log.info(SessionCachePrefixTest.class, "testCustomPrefix",
99+
"Successfully verified custom prefix 'testPrefix_' in cache names");
100+
} finally {
101+
server.stopServer("CWWKG0058E", "CWWKO0221E");
102+
}
103+
}
104+
105+
/**
106+
* Test Scenario 2: Empty string prefix
107+
* Verify that an empty string prefix behaves like the default (no prefix).
108+
*/
109+
@Test
110+
public void testEmptyStringPrefix() throws Exception {
111+
server.setServerConfigurationFile("server_emptyPrefix.xml");
112+
server.startServer();
113+
114+
try {
115+
List<String> session = new ArrayList<>();
116+
String sessionId = app.sessionPut("emptyKey", "emptyValue", session, true);
117+
assertNotNull("Session ID should not be null", sessionId);
118+
119+
// Verify session data can be retrieved
120+
app.sessionGet("emptyKey", "emptyValue", session);
121+
122+
// Check logs for standard cache name pattern (empty prefix should behave like default)
123+
assertNotNull("Should find standard cache name pattern in logs",
124+
server.waitForStringInTrace("com\\.ibm\\.ws\\.session\\.(attr|meta)\\.default_host", 30000));
125+
126+
Log.info(SessionCachePrefixTest.class, "testEmptyStringPrefix",
127+
"Successfully verified empty string prefix behaves like default");
128+
} finally {
129+
server.stopServer("CWWKG0058E", "CWWKO0221E");
130+
}
131+
}
132+
133+
/**
134+
* Test Scenario 3: Special characters in prefix
135+
* Verify that special characters (dash, underscore, dot, colon) work in prefix.
136+
*/
137+
@Test
138+
public void testSpecialCharactersInPrefix() throws Exception {
139+
server.setServerConfigurationFile("server_specialPrefix.xml");
140+
server.startServer();
141+
142+
try {
143+
List<String> session = new ArrayList<>();
144+
String sessionId = app.sessionPut("specialKey", "specialValue", session, true);
145+
assertNotNull("Session ID should not be null", sessionId);
146+
147+
// Verify session data can be retrieved
148+
app.sessionGet("specialKey", "specialValue", session);
149+
150+
// Check logs for prefix with special characters: "app-v1.2_prod:"
151+
assertNotNull("Should find prefix with special characters in cache names",
152+
server.waitForStringInTrace("app-v1\\.2_prod:com\\.ibm\\.ws\\.session\\.(attr|meta)", 30000));
153+
154+
Log.info(SessionCachePrefixTest.class, "testSpecialCharactersInPrefix",
155+
"Successfully verified special characters in prefix");
156+
} finally {
157+
server.stopServer("CWWKG0058E", "CWWKO0221E");
158+
}
159+
}
160+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<!--
2+
Copyright (c) 2026 IBM Corporation and others.
3+
All rights reserved. This program and the accompanying materials
4+
are made available under the terms of the Eclipse Public License 2.0
5+
which accompanies this distribution, and is available at
6+
http://www.eclipse.org/legal/epl-2.0/
7+
8+
SPDX-License-Identifier: EPL-2.0
9+
10+
Contributors:
11+
IBM Corporation - initial API and implementation
12+
-->
13+
<server>
14+
<featureManager>
15+
<feature>servlet-3.1</feature>
16+
<feature>componenttest-1.0</feature>
17+
<feature>bells-1.0</feature>
18+
<feature>sessionCache-1.0</feature>
19+
</featureManager>
20+
21+
<include location="../fatTestPorts.xml"/>
22+
23+
<httpSession maxInMemorySessionCount="1" allowOverflow="false" hideSessionValues="false"/>
24+
25+
<library id="HazelcastLib">
26+
<file name="${shared.resource.dir}/hazelcast/hazelcast.jar"/>
27+
</library>
28+
29+
<bell libraryRef="HazelcastLib" service="javax.cache.spi.CachingProvider"/>
30+
31+
<httpSessionCache cacheNamePrefix="testPrefix_"/>
32+
33+
<!-- Perms needed because the application uses Hazelcast directly -->
34+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.io.FilePermission" actions="read" name="${shared.resource.dir}/hazelcast/*"/>
35+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="accessClassInPackage.sun.management"/>
36+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="accessClassInPackage.com.sun.management.internal"/>
37+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="accessClassInPackage.sun.misc"/>
38+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="accessClassInPackage.sun.nio.ch"/>
39+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="accessDeclaredMembers"/>
40+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="enableContextClassLoaderOverride"/>
41+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="getClassLoader"/>
42+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="getenv.HZ_PHONE_HOME_ENABLED"/>
43+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="setContextClassLoader"/>
44+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.RuntimePermission" name="shutdownHooks"/>
45+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.lang.reflect.ReflectPermission" name="suppressAccessChecks"/>
46+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.net.NetPermission" name="getNetworkInformation"/>
47+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.net.SocketPermission" actions="connect,listen,resolve" name="*"/>
48+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="java.util.PropertyPermission" actions="read" name="*"/>
49+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="javax.management.MBeanPermission" actions="queryNames,registerMBean" name="*"/>
50+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="javax.management.MBeanServerPermission" name="createMBeanServer"/>
51+
<javaPermission codebase="${server.config.dir}/dropins/sessionCacheApp.war" className="javax.management.MBeanTrustPermission" name="register"/>
52+
</server>

0 commit comments

Comments
 (0)