Skip to content

Commit 06a6782

Browse files
committed
Update Spring dependencies
Add SSLBundle configuration option for Boot 3.1 apps (#94)
1 parent 0a9c072 commit 06a6782

30 files changed

Lines changed: 553 additions & 107 deletions

CHANGES.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
# Changelog
22
Newest updates are at the top of this file
33

4+
## 2.7.14 and 3.1.2 (2023-07-20)
5+
- Update Spring dependencies
6+
- Add SSLBundle configuration option for Boot 3.1 apps (#94)
7+
- Reverse build process to make Boot 3/Jakarta Messaging the default source tree
8+
49
## 2.7.13 and 3.1.1 (2023-06-22)
510
- Update Spring dependencies
611
- Update to MQ 9.3.3.0

README.md

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ and building it yourself, you can use the `RUNME.sh` script. It uses gradle as t
1515
push compiled jars to either a local repository (typically under `$HOME/.m2`) or to Maven Central.
1616
When signing/authentication of modules is required, use the `gradle.properties.template` file as a starter for your own `gradle.properties`.
1717

18-
Java 17 is required as the compiler level when building this package, as that is the baseline for Spring 3.
18+
Java 17 is required as the compiler level when building this package, as that is the baseline for Spring 3. Compiler directives are used to build
19+
the Spring 2 version as compatible with the older Java 8 runtime.
1920

20-
The script builds modules for both the JMS2 and JMS3 standards. The JMS3 (Jakarta) variant does not have a separate source tree in this repository. Instead, the source is generated automatically during the build process, by simply changing package names in the JMS2 code. The created jar files have the same names, but different version numbers.
21+
The script builds modules for both the JMS2 and JMS3 standards. The JMS3 (Jakarta) variant is the primary source. The older JMS2 version does not have a separate source tree in this repository. Instead, the source is generated automatically during the build process, by simply changing package names in the JMS3 code. The created jar files have the same names, but different version numbers.
2122

2223
### Spring Boot Applications
2324

@@ -67,8 +68,10 @@ IBM MQ for Developers container which runs the server processes.
6768
The default options have been selected to match the
6869
[MQ container](https://github.com/ibm-messaging/mq-container) development configuration.
6970

70-
This means that you can run a queue manager using that environment and connect to it. This script
71-
will run the container on a Linux system.
71+
This means that you can run a queue manager using that environment and connect to it without special
72+
configuration.
73+
74+
This script will run the container on a Linux system.
7275

7376
docker run --env LICENSE=accept --env MQ_QMGR_NAME=QM1 \
7477
--publish 1414:1414 \
@@ -193,7 +196,23 @@ and
193196
| ibm.mq.jks.keyStore | Where is the keystore with a personal key and certificate |
194197
| ibm.mq.jks.keyStorePassword | Password for the keyStore |
195198

196-
These JKS options are an alternative to setting the `javax.net.ssl` system properties.
199+
These JKS options are an alternative to setting the `javax.net.ssl` system properties, usually done on the command line.
200+
201+
An alternative preferred approach is
202+
available from Spring 3.1, which introduced the concept of "SSL Bundles". This makes it possible to have different
203+
SSL configurations - keystores, truststores etc - for different components executing in the same Spring-managed process.
204+
See [here](https://spring.io/blog/2023/06/07/securing-spring-boot-applications-with-ssl)
205+
for a description of the options available. Each bundle has an identifier with the `spring.ssl.bundle.jks.<key>` tree of options.
206+
The key can be specified for this package with `ibm.mq.sslBundle` which will then use the Spring elements to create the
207+
connection configuration. The default value for this key is empty, meaning that `SSLBundles` will not be used; the global
208+
SSL configuration is used instead.
209+
210+
| Option | Description |
211+
| ------------------------------- | ---------------------------------------------------------------------------- |
212+
| ibm.mq.sslBundle | Spring Boot option (from 3.1) for granular certificate configuration |
213+
214+
To achieve the same effect with Spring 2.x, you could use your own code to create an `SSLSocketFactory` object
215+
which can be applied to the MQ Connection Factory in a `customise` method before the CF is invoked.
197216

198217
#### Caching connection factory options
199218

@@ -202,14 +221,14 @@ preferred method in Spring for holding JMS objects open, rather than the Pooling
202221

203222
| Option | Description |
204223
| ----------------------------------- | ------------------------------------------------ |
205-
| spring.jms.cache.enabled | Whether to cache sessions |
224+
| spring.jms.cache.enabled | Whether to cache sessions (default true) |
206225
| spring.jms.cache.consumers | Whether to cache message consumers |
207226
| spring.jms.cache.producers | Whether to cache message producers |
208227
| spring.jms.cache.session-cache-size | Size of the session cache (per JMS Session type) |
209228

210229
#### Pooled connection factory options
211230

212-
Alternatively you may configure a pooled connection factory by using those properties:
231+
Alternatively you may configure a pooled connection factory by using these properties:
213232

214233
| Option | Description |
215234
| -------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
@@ -227,7 +246,7 @@ the options can be found [here](https://github.com/messaginghub/pooled-jms/blob/
227246

228247
### JMS Polling Listener Timer configuration
229248

230-
The Spring AbstractPollingMessageListenerContainer interface has a default polling timer of 1 second. This can now be configured
249+
The Spring AbstractPollingMessageListenerContainer interface has a default polling timer of 1 second. This can be configured
231250
with the `spring.jms.listener.receiveTimeout` property. If the property is not explicitly set, then this MQ Spring Boot
232251
component resets the initial timeout value to 30 seconds which has been shown to be more cost-effective. Application code
233252
can still set its own preferred value.

RUNME.sh

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,12 @@ EOF
4040
}
4141

4242
function makeJms3Source {
43-
$curdir/makeJms3.sh $1 $2
43+
# This is the primary version, so don't need to copy it
4444
majors="$majors 61"
4545
}
4646

4747
function makeJms2Source {
48-
# There's nothing much needed here. Just make sure
49-
# we know what version of compiler to expect.
48+
$curdir/makeJms2.sh $1 $2
5049
majors="$majors 52"
5150
}
5251

@@ -60,8 +59,9 @@ buildLog="/tmp/springBuild.log"
6059
rcFile="/tmp/springBuild.rc"
6160
majorsFile="/tmp/springBuild.majors"
6261

62+
# Definitions for how to create the variation
6363
in="$curdir/mq-jms-spring-boot-starter"
64-
out="$curdir/mq-jms3-spring-boot-starter"
64+
out="$curdir/mq-jms2-spring-boot-starter"
6565

6666
majors=""
6767

@@ -129,9 +129,9 @@ for vers in $jmsVersions
129129
do
130130
if [ $vers = "jms3" ]
131131
then
132-
makeJms3Source $in $out
132+
makeJms3Source
133133
else
134-
makeJms2Source
134+
makeJms2Source $in $out
135135
fi
136136

137137
cd $curdir
@@ -150,7 +150,7 @@ do
150150
then
151151
cp $HOME/.gradle.properties ./gradle.properties
152152
else
153-
cp gradle.properties.template gradle.properties
153+
cp -p gradle.properties.template gradle.properties
154154
fi
155155

156156
if [ ! -r gradle.properties ]
@@ -163,7 +163,7 @@ do
163163
(./gradlew $args --warning-mode all clean jar $target 2>&1;echo $? > $rcFile) | tee -a $buildLog
164164

165165
# Always make sure we've got a dummy properties file - the values are not needed from here on
166-
cp gradle.properties.template gradle.properties
166+
cp -p gradle.properties.template gradle.properties
167167

168168
# Now we can look for errors
169169
rc=`cat $rcFile`

build.gradle

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2018,2022 IBM Corp. All rights reserved.
2+
* Copyright 2018,2023 IBM Corp. All rights reserved.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
55
* except in compliance with the License. You may obtain a copy of the License at
@@ -21,10 +21,10 @@
2121
* The "JMSVERSION" environment variable can be set to "jms2" or "jms3" and that is used
2222
* as the prefix for various control files and processing steps. We only build a single version
2323
* from this file; to build both jms2 and jms3, you have to run gradle twice.
24-
* The default is "jms2" if the env var is not set.
24+
* The default is "jms3" if the env var is not set.
2525
*/
2626
ext.jmsVersionProperty = 'JMSVERSION'
27-
ext.jmsVer = (System.getenv(jmsVersionProperty)== null?'jms2':System.getenv(jmsVersionProperty))
27+
ext.jmsVer = (System.getenv(jmsVersionProperty)== null?'jms3':System.getenv(jmsVersionProperty))
2828
ext.propsFile = new File(rootDir, jmsVer + '.properties')
2929

3030
// Now we know the jms Version, load the specific properties
@@ -44,12 +44,12 @@ subprojects {
4444
group = mqGroup
4545
version = mqStarterVersion
4646

47-
// Include the Spring milestone repository so we get early drops of the Jakarta-based version
47+
// Could enable access to early-release Spring packages if we need it
4848
repositories {
4949
mavenLocal()
5050

5151
//maven { url "https://repo.spring.io/snapshot" }
52-
maven { url "https://repo.spring.io/milestone" }
52+
//maven { url "https://repo.spring.io/milestone" }
5353

5454
mavenCentral()
5555
}

makeJms2.sh

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/bash
2+
3+
# Generate JMS2 source from the JMS3:
4+
#
5+
# This script creates a copy of the Boot Starter code which is functionally (almost) identical
6+
# but has the jakarta package names replaced by javax in most places.
7+
8+
curdir=`pwd`
9+
in="$1"
10+
out="$2"
11+
12+
if [ -z "$in" -o -z "$out" ]
13+
then
14+
echo "Usage: makeJms2.sh inDir outDir"
15+
exit 1
16+
fi
17+
# echo "Copying files for JMS2 build from $in to $out"
18+
19+
if [ ! -d $in ]
20+
then
21+
echo "Cannot find input directory $in"
22+
exit 1
23+
fi
24+
25+
mkdir $out >/dev/null 2>&1
26+
cd $in
27+
# Create the structure
28+
find . -type f | grep -v ".jms3" | cpio -upad $out
29+
# And recopy the files doing the package renaming as we go
30+
find . -type f -name "*.java" | while read f
31+
do
32+
# Change various package names to replace jakarta with javax in most places.
33+
# But the original MQ package names have neither in there.
34+
cat $f |\
35+
grep -v "DeprecatedConfigurationProperty" |\
36+
sed "s/jakarta/javax/g" |\
37+
sed "s/ibm.mq.javax/ibm.mq/g" |\
38+
sed "s/ibm.msg.client.javax/ibm.msg.client/g "> $out/$f
39+
done
40+
41+
find src -type f -name "*.jms2" | while read f
42+
do
43+
# echo $f
44+
d=`dirname $f`
45+
n=`echo $f | sed "s/.jms2$//g"`
46+
cp $f $out/$n
47+
done
48+
49+
# One final piece of patching is for the SSLBundles support only available from Spring Boot 3.1
50+
f="./src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"
51+
cat $f | grep -v "com.ibm.mq.spring.boot.MQConfigurationSslBundles" > $out/$f

makeJms3.sh

Lines changed: 0 additions & 43 deletions
This file was deleted.

mq-jms-spring-boot-starter/src/main/java/com/ibm/mq/spring/boot/MQAutoConfiguration.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
package com.ibm.mq.spring.boot;
1616

17-
import javax.jms.ConnectionFactory;
17+
import jakarta.jms.ConnectionFactory;
1818

1919
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
2020
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
@@ -29,15 +29,15 @@
2929
import org.springframework.context.annotation.Configuration;
3030
import org.springframework.context.annotation.Import;
3131

32-
import com.ibm.mq.jms.MQConnectionFactory;
32+
import com.ibm.mq.jakarta.jms.MQConnectionFactory;
3333

3434
// See https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-3.0.0-M5-Release-Notes
3535
// where autoconfiguration was moved from META-INF/spring.factories to a separate file. The
3636
// original file can remain in place though for both Boot 2 and Boot 3.
3737

3838
@Configuration(proxyBeanMethods=false)
3939
@AutoConfigureBefore(JmsAutoConfiguration.class)
40-
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class, JtaAutoConfiguration.class})
40+
@AutoConfigureAfter({ JndiConnectionFactoryAutoConfiguration.class, JtaAutoConfiguration.class,MQConfigurationSslBundles.class})
4141
@ConditionalOnClass({ ConnectionFactory.class, MQConnectionFactory.class })
4242
@ConditionalOnProperty(prefix = "ibm.mq", name = "autoConfigure", matchIfMissing=true)
4343
@ConditionalOnMissingBean(ConnectionFactory.class)

mq-jms-spring-boot-starter/src/main/java/com/ibm/mq/spring/boot/MQConfigurationProperties.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,18 @@
2323
import org.springframework.boot.context.properties.ConfigurationProperties;
2424
import org.springframework.boot.context.properties.NestedConfigurationProperty;
2525

26-
import com.ibm.msg.client.wmq.WMQConstants;
26+
import com.ibm.msg.client.jakarta.wmq.WMQConstants;
2727

2828
/**
29-
* There are many properties that can be set on an MQ Connection Factory, but these are the most commonly-used
30-
* for both direct and client connections. If you use TLS for client connectivity, most properties related to that
31-
* (keystore, certificates etc) must be set independently.
29+
* There are many properties that can be set on an MQ Connection Factory/ This class allows configuration for most of them
30+
* for both direct and client connections. Any that are not explicitly named in here can be managed through the "additionalProperties"
31+
* map.
3232
* <p>
3333
* This class allows for setting the CipherSuite/CipherSpec property, and an indication of whether or not
3434
* to use the IBM JRE maps for Cipher names - that's not something that is standardised.
3535
* <p>
3636
* The default values have been set to match the settings of the
37-
* <a href="https://github.com/ibm-messaging/mq-docker">MQ Docker</a>
38-
* container.
37+
* <a href="https://github.com/ibm-messaging/mq-container">developer-configured container</a>.
3938
*
4039
* <ul>
4140
* <li>queueManager = QM1
@@ -187,6 +186,10 @@ public class MQConfigurationProperties {
187186
*/
188187
private int sslKeyResetCount = -1;
189188

189+
/**
190+
* The key to the SSL Bundle attributes available from Spring Boot 3.1
191+
*/
192+
private String sslBundle;
190193

191194
/**
192195
* Additional CF properties that are not explicitly known can be provided
@@ -396,6 +399,14 @@ public int getSslKeyResetCount() {
396399
public void setSslKeyResetCount(int sslKeyResetCount) {
397400
this.sslKeyResetCount = sslKeyResetCount;
398401
}
402+
403+
public String getSslBundle() {
404+
return sslBundle;
405+
}
406+
407+
public void setSslBundle(String sslBundle) {
408+
this.sslBundle = sslBundle;
409+
}
399410

400411
public int getReconnectValue() {
401412
int rc = 0;
@@ -451,6 +462,8 @@ public void traceProperties() {
451462
logger.trace("sslCipherSuite : {}", getSslCipherSuite());
452463
logger.trace("sslKeyresetcount: {}", getSslKeyResetCount());
453464
logger.trace("sslPeerName : {}", getSslPeerName());
465+
logger.trace("sslBundle : {}",getSslBundle());
466+
454467
logger.trace("tempModel : {}", getTempModel());
455468
logger.trace("tempQPrefix : {}", getTempQPrefix());
456469
logger.trace("tempTopicPrefix : {}", getTempTopicPrefix());
@@ -463,7 +476,6 @@ public void traceProperties() {
463476
logger.trace("outboundSNI : \'{}\'", getOutboundSNI());
464477
logger.trace("channelSharing : \'{}\'", getChannelSharing());
465478

466-
467479
logger.trace("jndiCF : {}", getJndi().getProviderContextFactory());
468480
logger.trace("jndiProviderUrl : {}", getJndi().getProviderUrl());
469481

@@ -473,7 +485,7 @@ public void traceProperties() {
473485
pw = getJks().getTrustStorePassword();
474486
logger.trace("JKS truststore : {}",getJks().getTrustStore());
475487
logger.trace("JKS truststore pw set : {}", (pw != null && pw.length() > 0) ? "YES" : "NO");
476-
488+
477489
if (additionalProperties.size() > 0) {
478490
for (String s: additionalProperties.keySet()) {
479491
logger.trace("Additional Property - {} : {}",s,additionalProperties.get(s));

mq-jms-spring-boot-starter/src/main/java/com/ibm/mq/spring/boot/MQConfigurationPropertiesJks.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public String getTrustStore() {
5353
public void setTrustStore(String trustStore) {
5454
this.trustStore = trustStore;
5555
}
56-
56+
5757
public String getKeyStorePassword() {
5858
return keyStorePassword;
5959
}

0 commit comments

Comments
 (0)