Skip to content

Commit

Permalink
[WINDUPRULE-1042] Implement JMS to Quarkus rules (#1043)
Browse files Browse the repository at this point in the history
* [WINDUPRULE-1042] Implement JMS to Quarkus rules

Signed-off-by: Juan Manuel Leflet Estrada <[email protected]>

* [WINDUPRULE-1042] Refactor names

Signed-off-by: Juan Manuel Leflet Estrada <[email protected]>

* [WINDUPRULE-1042] Improve rules, fix test

Signed-off-by: Juan Manuel Leflet Estrada <[email protected]>

* [WINDUPRULE-1042] Fix tests

Signed-off-by: Juan Manuel Leflet Estrada <[email protected]>

---------

Signed-off-by: Juan Manuel Leflet Estrada <[email protected]>
(cherry picked from commit 40d3c19)
  • Loading branch information
jmle committed Dec 12, 2023
1 parent 5e32440 commit 79a1966
Show file tree
Hide file tree
Showing 8 changed files with 700 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
<?xml version="1.0"?>
<ruleset xmlns="http://windup.jboss.org/schema/jboss-ruleset" id="jms-to-reactive-quarkus"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://windup.jboss.org/schema/jboss-ruleset http://windup.jboss.org/schema/jboss-ruleset/windup-jboss-ruleset.xsd">
<metadata>
<description>
This ruleset gives hints to migrate from JMS to a reactive messaging model in Quarkus.
</description>
<dependencies>
<addon id="org.jboss.windup.rules,windup-rules-javaee,3.0.0.Final" />
<addon id="org.jboss.windup.rules,windup-rules-java,3.0.0.Final" />
<addon id="org.jboss.windup.rules,windup-rules-xml,3.0.0.Final" />
</dependencies>
<sourceTechnology id="java-ee" />
<targetTechnology id="quarkus" />
</metadata>
<rules>
<rule id="jms-to-reactive-quarkus-00000">
<when>
<or>
<project>
<artifact groupId="jakarta.jms" artifactId="jakarta.jms-api"/>
</project>
<project>
<artifact groupId="javax.jms" artifactId="javax.jms-api"/>
</project>
</or>
</when>
<perform>
<hint title="JMS is not supported in Quarkus" effort="5" category-id="mandatory">
<message>
<![CDATA[
Usage of JMS is not supported in Quarkus. It is recommended to use Quarkus' SmallRye Reactive Messaging instead of JMS.
Replace the JavaEE/Jakarta JMS dependency with Smallrye Reactive:
```
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-reactive-messaging</artifactId>
</dependency>
```
Take a look at the Smallrye Reactive Connectors link below to know more about how to interact with different technologies (AMQP, Apache Camel, ...)
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
<link title="Smallrye Reactive - Connectors" href="https://smallrye.io/smallrye-reactive-messaging/smallrye-reactive-messaging/3.4/connectors/connectors.html" />
</hint>
</perform>
</rule>
<rule id="jms-to-reactive-quarkus-00010">
<when>
<or>
<javaclass references="javax.ejb.MessageDriven">
<location>ANNOTATION</location>
</javaclass>
<javaclass references="jakarta.ejb.MessageDriven">
<location>ANNOTATION</location>
</javaclass>
</or>
</when>
<perform>
<hint title="@MessageDriven - EJBs are not supported in Quarkus" effort="3" category-id="mandatory">
<message>
<![CDATA[
Enterprise Java Beans (EJBs) are not supported in Quarkus. CDI must be used.
Please replace the `@MessageDriven` annotation with a CDI scope annotation like `@ApplicationScoped`.
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
</hint>
</perform>
</rule>
<rule id="jms-to-reactive-quarkus-00020">
<when>
<or>
<javaclass references="javax.ejb.ActivationConfigProperty">
<location>ANNOTATION</location>
<annotation-literal name="propertyName" pattern="destinationLookup"/>
</javaclass>
<javaclass references="jakarta.ejb.ActivationConfigProperty">
<location>ANNOTATION</location>
<annotation-literal name="propertyName" pattern="destinationLookup"/>
</javaclass>
</or>
</when>
<perform>
<hint title="Configure message listener method with @Incoming" effort="3" category-id="mandatory">
<message>
<![CDATA[
The `destinationLookup` property can be migrated by annotating a message handler method (potentially `onMessage`) with the
`org.eclipse.microprofile.reactive.messaging.Incoming` annotation, indicating the name of the queue as a value:
Before:
```
@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/HELLOWORLDMDBQueue")
}
public class MessageListenerImpl implements MessageListener {
public void onMessage(Message msg) {
// ...handler code
}
}
```
After:
```
public class MessageListenerImpl implements MessageListener {
@Incoming("HELLOWORLDMDBQueue")
public void onMessage(String message) {
// ...handler code
}
}
```
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
<link title="Incoming (SmallRye Reactive Messaging API)" href="https://smallrye.io/smallrye-reactive-messaging/2.5.0/apidocs/org/eclipse/microprofile/reactive/messaging/Incoming.html"/>
</hint>
</perform>
</rule>
<rule id="jms-to-reactive-quarkus-00030">
<when>
<or>
<javaclass references="javax.jms.Queue">
<location>FIELD_DECLARATION</location>
</javaclass>
<javaclass references="jakarta.jms.Queue">
<location>FIELD_DECLARATION</location>
</javaclass>
</or>
</when>
<perform>
<hint title="JMS' Queue must be replaced with an Emitter" effort="3" category-id="mandatory">
<message>
<![CDATA[
JMS `Queue`s should be replaced with Micrometer `Emitter`s feeding a Channel. See the following example of migrating
a Queue to an Emitter:
Before:
```
@Resource(lookup = "java:/queue/HELLOWORLDMDBQueue")
private Queue queue;
```
After:
```
@Inject
@Channel("HELLOWORLDMDBQueue")
Emitter<String> queueEmitter;
```
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
<link title="Emitter (Microprofile Reactive Streams Messaging)" href="https://smallrye.io/smallrye-reactive-messaging/2.0.2/apidocs/org/eclipse/microprofile/reactive/messaging/Emitter.html" />
</hint>
</perform>
</rule>
<rule id="jms-to-reactive-quarkus-00040">
<when>
<or>
<javaclass references="javax.jms.Topic">
<location>FIELD_DECLARATION</location>
</javaclass>
<javaclass references="jakarta.jms.Topic">
<location>FIELD_DECLARATION</location>
</javaclass>
</or>
</when>
<perform>
<hint title="JMS' Topic must be replaced with an Emitter" effort="3" category-id="mandatory">
<message>
<![CDATA[
JMS `Topic`s should be replaced with Micrometer `Emitter`s feeding a Channel. See the following example of migrating
a Topic to an Emitter:
Before:
```
@Resource(lookup = "java:/topic/HELLOWORLDMDBTopic")
private Topic topic;
```
After:
```
@Inject
@Channel("HELLOWORLDMDBTopic")
Emitter<String> topicEmitter;
```
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
<link title="Emitter (Microprofile Reactive Streams Messaging)" href="https://smallrye.io/smallrye-reactive-messaging/2.0.2/apidocs/org/eclipse/microprofile/reactive/messaging/Emitter.html" />
</hint>
</perform>
</rule>
<rule id="jms-to-reactive-quarkus-00050">
<when>
<or>
<javaclass references="javax.jms{*}"/>
<javaclass references="jakarta.jms{*}"/>
</or>
</when>
<perform>
<hint title="JMS is not supported in Quarkus" effort="5" category-id="mandatory">
<message>
<![CDATA[
References to JavaEE/JakartaEE JMS elements should be removed and replaced with their Quarkus SmallRye/Microprofile equivalents.
]]>
</message>
<link title="Quarkus - Guide" href="https://quarkus.io/guides" />
</hint>
</perform>
</rule>
</rules>
</ruleset>
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
<rule id="cdi-to-quarkus-groovy-00030-test">
<when>
<not>
<iterable-filter size="1">
<iterable-filter size="2">
<hint-exists message="The application has a transitive `javax.inject:javax.inject` dependency because at least one Java class that imports from the `javax.inject` has been found"/>
</iterable-filter>
</not>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* Licensed 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.
*/
package org.jboss.as.quickstarts.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.annotation.Resource;
import javax.inject.Inject;
import javax.jms.Destination;
import javax.jms.JMSContext;
import javax.jms.JMSDestinationDefinition;
import javax.jms.JMSDestinationDefinitions;
import javax.jms.Queue;
import javax.jms.Topic;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* Definition of the two JMS destinations used by the quickstart
* (one queue and one topic).
*/
@JMSDestinationDefinitions(
value = {
@JMSDestinationDefinition(
name = "java:/queue/HELLOWORLDMDBQueue",
interfaceName = "javax.jms.Queue",
destinationName = "HelloWorldMDBQueue"
),
@JMSDestinationDefinition(
name = "java:/topic/HELLOWORLDMDBTopic",
interfaceName = "javax.jms.Topic",
destinationName = "HelloWorldMDBTopic"
)
}
)

/**
* <p>
* A simple servlet 3 as client that sends several messages to a queue or a topic.
* </p>
*
* <p>
* The servlet is registered and mapped to /HelloWorldMDBServletClient using the {@linkplain WebServlet
* @HttpServlet}.
* </p>
*
* @author Serge Pagop ([email protected])
*
*/
@WebServlet("/HelloWorldMDBServletClient")
public class HelloWorldMDBServletClient extends HttpServlet {

private static final long serialVersionUID = -8314035702649252239L;

private static final int MSG_COUNT = 5;

@Inject
private JMSContext context;

@Resource(lookup = "java:/queue/HELLOWORLDMDBQueue")
private Queue queue;

@Resource(lookup = "java:/topic/HELLOWORLDMDBTopic")
private Topic topic;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");
PrintWriter out = resp.getWriter();
out.write("<h1>Quickstart: Example demonstrates the use of <strong>JMS 2.0</strong> and <strong>EJB 3.2 Message-Driven Bean</strong> in JBoss EAP.</h1>");
try {
boolean useTopic = req.getParameterMap().keySet().contains("topic");
final Destination destination = useTopic ? topic : queue;

out.write("<p>Sending messages to <em>" + destination + "</em></p>");
out.write("<h2>The following messages will be sent to the destination:</h2>");
for (int i = 0; i < MSG_COUNT; i++) {
String text = "This is message " + (i + 1);
context.createProducer().send(destination, text);
out.write("Message (" + i + "): " + text + "</br>");
}
out.write("<p><i>Go to your JBoss EAP server console or server log to see the result of messages processing.</i></p>");
} finally {
if (out != null) {
out.close();
}
}
}

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual
* contributors by the @authors tag. See the copyright.txt in the
* distribution for a full listing of individual contributors.
*
* Licensed 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.
*/
//package org.jboss.as.quickstarts.mdb;

import java.util.logging.Logger;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

/**
* <p>
* A simple Message Driven Bean that asynchronously receives and processes the messages that are sent to the queue.
* </p>
*
* @author Serge Pagop ([email protected])
*/
@MessageDriven(name = "HelloWorldQueueMDB", activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "queue/HELLOWORLDMDBQueue"),
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class HelloWorldQueueMDB implements MessageListener {

private static final Logger LOGGER = Logger.getLogger(HelloWorldQueueMDB.class.toString());

/**
* @see MessageListener#onMessage(Message)
*/
public void onMessage(Message rcvMessage) {
TextMessage msg = null;
try {
if (rcvMessage instanceof TextMessage) {
msg = (TextMessage) rcvMessage;
LOGGER.info("Received Message from queue: " + msg.getText());
} else {
LOGGER.warning("Message of wrong type: " + rcvMessage.getClass().getName());
}
} catch (JMSException e) {
throw new RuntimeException(e);
}
}
}
Loading

0 comments on commit 79a1966

Please sign in to comment.