Where to define setTrustAllPackages=true in #MessageDriven bean in external ActiveMQ - serialization

I am doing a Publish - Subscribe using external ActiveMQ (5.15.10). My application is deployed on TomEE 8.0.1 server and ActiveMQ configurations are done in tomee.xml.
I am able publish the message successfully but while receiving messages am facing issues. In onMessage method I need to process a pojo and I get below error
"This class is not trusted to be serialized as ObjectMessage payload"
I use EclipseLink JPA in my application and I need to send the pojo that I receive in onMessage method to my #Stateless bean (here UserService) to process it further. So, UserService is injected with #EJB annotation in my MDBSubscriber class below.
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(
propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(
propertyName = "destination",
propertyValue = "userQueue")
}
)
public class MDBSubscriber implements MessageListener {
#EJB
UserService uService;
public void onMessage(Message msg) {
if(msg instanceof ObjectMessage) {
ObjectMessage objMsg = (ObjectMessage) msg;
UserForm uForm= (UserForm) objMsg.getObject();
----
----
uService.process(uForm);
}
}
}
When I read through ActiveMQ docs, it says setTrustAllPackages=true can be set on ActiveMQConnectionFactory object but since am using #MessageDriven Bean I don't have ActiveMQConnectionFactory object in my class defined above.
So, my problem is where or how do we define setTrustAllPackages=true in #MessageDriven Bean?
I am stuck with this problem since more than 10 days and could not find a solution.
Can someone help me here ?

You can configure this via a system property as well which avoids the trustAllPackages connection factory option. There is documentation for this already on the ActiveMQ site.
In case you want to shortcut this mechanism, you can allow all packages to be trusted by using * wildcard, like
-Dorg.apache.activemq.SERIALIZABLE_PACKAGES=*

Related

jax-rs sse client with Singleton in Glassfish/Payara

About jax-rs client with SSE in EJB Singleton, I've tried with Payara server full-5.183 (without docker) for this example, [https://abhirockzz.wordpress.com/2017/07/27/jax-rs-2-1-sse-client-api-example-using-glassfish-5-on-docker/], but failed. Error shown at line eventSource = SseEventSource.target(target).build();
#PostConstruct
public void init() {
this.sseClient = ClientBuilder.newClient();
this.target = this.sseClient.target("https://sse.now.sh");
tsvc.createSingleActionTimer(15000, null);
System.out.println("SSE client timer created");
eventSource = SseEventSource.target(target).build();
System.out.println("SSE Event source created........");
}
Error message: "java.lang.IllegalArgumentException: Argument fish.payara.requesttracing.jaxrs.client.decorators.JaxrsWebTargetDecorator#23112ded is not a valid JerseyWebTarget instance. SseEventSource does not support other WebTarget implementations."
Can anyone give me an idea?

spring cloud stream unable to parse message posted to RabbitMq using Spring RestTemplate

I have an issue in getting the message to spring-cloud-stream spring-boot app.
I am using rabbitMq as message engine.
Message producer is a non spring-boot app, which sends a message using Spring RestTemplate.
Queue Name: "audit.logging.rest"
The consumer application is setup to listen that queue. This app is spring-boot app(spring-cloud-stream).
Below is the consumer code
application.yml
cloud:
stream:
bindings:
restChannel:
binder: rabbit
destination: audit.logging
group: rest
AuditServiceApplication.java
#SpringBootApplication
public class AuditServiceApplication {
#Bean
public ByteArrayMessageConverter byteArrayMessageConverter() {
return new ByteArrayMessageConverter();
}
#Input
#StreamListener(AuditChannelProperties.REST_CHANNEL)
public void receive(AuditTestLogger logger) {
...
}
AuditTestLogger.java
public class AuditTestLogger {
private String applicationName;
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
}
Below is the request being sent from the producer App in JSON format.
{"applicationName" : "AppOne" }
Found couple of issues:
Issue1:
What I noticed is the below method is getting triggered only when the method Parameter is mentioned as Object, as spring-cloud-stream is not able to parse the message into Java POJO object.
#Input
#StreamListener(AuditChannelProperties.REST_CHANNEL)
public void receive(AuditTestLogger logger) {
Issue2:
When I changed the method to receive object. I see the object is of type RMQTextMessage which cannot be parsed. However I see actual posted message within it against text property.
I had written a ByteArrayMessageConverter which even didn't help.
Is there any way to tell spring cloud stream to extract the message from RMQTextMessage using MessageConverter and get the actual message out of it.
Thanks in Advance..
RMQTextMessage? Looks like it is a part of rabbitmq-jms-client.
In case of RabbitMQ Binder you should rely only on the Spring AMQP.
Now let's figure out what your producer application is doing.
Since you get RMQTextMessage as value for the #StreamListener method that says me that the sender really uses rabbitmq-jms-client for producing, and therefore the real AMQP message in queue has that RMQTextMessage as a wrapper for real payload.
Why don't use Spring AMQP there as well?
It's a late reply but I have the exact problem and solved it by sending and receiving the messages in application/json format. use this in the spring cloud stream config.
content-type: application/json

ActiveMQ, Wildfly and get message body (getBody)

I am new to JEE7 and have been working on some quick exercises but I've bumped into a problem. I have a sample Java SE application that sends a message to an ActiveMQ queue and I have an MDB deployed on Wildfly 8 that reads the messages as they come in. This all works fine and I can receive the messages using getText. However, when I use getBody to get the message body, I get an "Unknown Error". Can anyone let me know what I'm doing wrong?
Here's my code below;
/***CLIENT CODE****/
import javax.jms.*;
import org.apache.activemq.ActiveMQConnection;
import org.apache.activemq.ActiveMQConnectionFactory;
public class SimpleMessageClient {
// URL of the JMS server. DEFAULT_BROKER_URL will just mean
// that JMS server is on localhost
private static String url = ActiveMQConnection.DEFAULT_BROKER_URL;
// Name of the queue we will be sending messages to
private static String subject = "MyQueue";
public static void main(String[] args) throws JMSException {
// Getting JMS connection from the server and starting it
ConnectionFactory connectionFactory =
new ActiveMQConnectionFactory(url);
Connection connection = connectionFactory.createConnection();
connection.start();
// JMS messages are sent and received using a Session. We will
// create here a non-transactional session object. If you want
// to use transactions you should set the first parameter to 'true'
Session session = connection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
// Destination represents here our queue 'TESTQUEUE' on the
// JMS server. You don't have to do anything special on the
// server to create it, it will be created automatically.
Destination destination = session.createQueue(subject);
// MessageProducer is used for sending messages (as opposed
// to MessageConsumer which is used for receiving them)
MessageProducer producer = session.createProducer(destination);
// We will send a small text message saying 'Hello' in Japanese
TextMessage message = session.createTextMessage("Jai Hind");
//Message someMsg=session.createMessage();
// someMsg.
// Here we are sending the message!
producer.send(message);
System.out.println("Sent message '" + message.getText() + "'");
connection.close();
}
}
And the consumer;
package javaeetutorial.simplemessage.ejb;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.ejb.MessageDrivenContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "MyQueue")
})
public class SimpleMessageBean implements MessageListener {
#Resource
private MessageDrivenContext mdc;
static final Logger logger = Logger.getLogger("SimpleMessageBean");
public SimpleMessageBean() {
}
#Override
public void onMessage(Message inMessage) {
try {
if (inMessage instanceof TextMessage) {
logger.log(Level.INFO,
"MESSAGE BEAN: Message received: {0}",
inMessage.getBody(String.class));
} else {
logger.log(Level.WARNING,
"Message of wrong type: {0}",
inMessage.getClass().getName());
}
} catch (JMSException e) {
e.printStackTrace();
logger.log(Level.SEVERE,
"SimpleMessageBean.onMessage: JMSException: {0}",
e.toString());
mdc.setRollbackOnly();
}
}
}
Part of the error I get is;
16:47:48,510 ERROR [org.jboss.as.ejb3] (default-threads - 32) javax.ejb.EJBTransactionRolledbackException: Unexpected Error
16:47:48,511 ERROR [org.jboss.as.ejb3.invocation] (default-threads - 32) JBAS014134: EJB Invocation failed on component SimpleMessageBean for method public void javaeetutorial.simplemessage.ejb.SimpleMessageBean.onMessage(javax.jms.Message): javax.ejb.EJBTransactionRolledbackException: Unexpected Error
at org.jboss.as.ejb3.tx.CMTTxInterceptor.handleInCallerTx(CMTTxInterceptor.java:157) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:253) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
at org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:342) [wildfly-ejb3-8.2.0.Final.jar:8.2.0.Final]
The method
<T> T Message.getBody(Class<T> c)
you refer to was an addition to JMS 2.0 (see also: http://www.oracle.com/technetwork/articles/java/jms20-1947669.html).
While WildFly 8 is fully compliant to Java EE 7 and therefore JMS 2.1, the current ActiveMQ (5.12.0) is still restricted to JMS 1.1.
Since you presumably import the JMS 2.1 API in your SimpleMessageBean, you reference a method simply not present in the ActiveMQ message.
When you try to call the getBody()-method on the message, it cannot be resolved in the message implementation and hence an AbstractMethodError is thrown. This results in the rollback of the transaction which gives you the EJBTransactionRolledbackException.
I see two immediate solutions for your problem:
If you want to keep using ActiveMQ, confine yourself to the JMS 1.1 API. The getText()-method you mentioned is part of JMS 1.1 and therefore works flawlessly. See here for the JMS 1.1 API (https://docs.oracle.com/javaee/6/api/javax/jms/package-summary.html) and here for the current ActiveMQ API documentation (http://activemq.apache.org/maven/5.12.0/apidocs/index.html).
Switch to a JMS 2.x compliant message broker. Since you are using WildFly, I recommend taking a look at HornetQ (http://hornetq.jboss.org/).

EJB Injection failure on deploy

I've got a problem exxh EJB's.
First of all, my setup: I am using GlassFish & JEE6. I have got a REST-Service packaged as a WAR and a bean packaged as an EJB-Jar. They are not inside an EAR.
The EJB should be used from the REST-WAR via #EJB, but when I try to deploy the WAR, GlassFish shows this error:
Error occurred during deployment:
Exception while deploying the app [exx-upload-1.0] : Cannot resolve reference Local ejb-ref name=com.ex.exx.model.FileUpload/ocr,Local 3.x interface =com.ex.exx.api.IOCRService,ejb-link=null,lookup=,mappedName=,jndi-name=,refType=Session. Please see server.log for more details.
(The EJB was deployed before without any erros).
I have no clue why. Here is the EJB Code:
Interface:
#Local
public interface IOCRService {
public String performOCRonImage(BufferedImage input);
}
and Implementation:
#Stateless
#LocalBean
public class OCRScanner implements IOCRService {
private Logger logger = Logger.getLogger(this.getClass().getName());
private final static String NOT_RECOGNIZED = "Can not regocnize text";
/**
* Default constructor.
*/
public OCRScanner() {
logger.log(Level.INFO, "### OCR SCANNER BUILD" + this);
}
public String performOCRonImage(BufferedImage input) {
logger.log(Level.INFO, "### OCR SCANNER CALLED" + this);
}
...
And here is the important part in the WAR:
public class FileUpload {
private final File PROPERTIES_FILE = new File(
"fileUploadProperties.properties");
private final String PARAMETER_NAME = "file";
private final Logger logger = Logger.getLogger(this.getClass().getName());
#EJB
private IOCRService ocr;
public Response uploadFile(...) {
// do some stuff
logger.log(Level.INFO, "### EJB" + ocr.toString())
}
Anny suggestions? I can not find my failure here.
Solved this, by replaceing #Local with #Remote.
This works, however, I am not satisfied as I do not understand why.
Basically, given the specs (eg. explained in the tutorial), an application can only access other application's EJB, if they are decorated with #Remote.
Thus, you have 3 options:
decorate your EJB with #Remote (what you have done),
package both together inside an ear (as they would reside in the
same application then). But if you intent to deploy them in seperate
applications or even seperate servers, use 1.)
use CDI with #Inject, but this will still only discover the EJB if
either in the same application, or decorated as #Remote if not.
HTH,
Alex
You should not use #EJB if the target is not an EJB. I guess this is your case because you are trying to inject into a class in your WAR.
Instead use:
#Inject
private IOCRService ocr;
Basically, #Inject is better in most cases, because:
it is more typesafe,
it supports #Alternatives
it is aware of the scope of the injected object.
Another solution it's to add #Stateless(name=""), this worked form

Is there a global exception handler for NServiceBus?

The current advice on handling exceptions in NServiceBus is to use the built in facilities. Errored out messages go to the error message queue, and a log is written to disk.
But what if I want to send my errors to a service like AirBrake which has better functionality for grouping similar exceptions, metrics, and other good stuff? Is there a global exception handler I can tap into?
As mentioned in the original post the recommended solution is to use ServicePulse for monitoring errors. The client I currently work for is using a custom made centralized logger, and we want NServiceBus to log to this log store when messages are forwarded to the error queue.
We could have achieved this by just editing the log4net config if the exception from NServiceBus had included the original exception, currently NServiceBus just logs a generic error message with no details about what caused the failure.
NServiceBus has a class named NServiceBus.Faults.ErrorsNotifications which contains the following observables:
MessageSentToErrorQueue
MessageHasFailedAFirstLevelRetryAttempt
MessageHasBeenSentToSecondLevelRetries
You can subscribe to these observables when the endpoint starts, like in the following example which logs an error when messages are sent to the error queue:
public class GlobalErrorHandler : IWantToRunWhenBusStartsAndStops
{
private readonly ILogger _logger;
private readonly BusNotifications _busNotifications;
readonly List<IDisposable> _notificationSubscriptions = new List<IDisposable>();
public GlobalErrorHandler(ILogger logger, BusNotifications busNotifications)
{
_logger = logger;
_busNotifications = busNotifications;
}
public void Start()
{
_notificationSubscriptions.Add(_busNotifications.Errors.MessageSentToErrorQueue.Subscribe(LogWhenMessageSentToErrorQueue));
}
public void Stop()
{
foreach (var subscription in _notificationSubscriptions)
{
subscription.Dispose();
}
}
private void LogWhenMessageSentToErrorQueue(FailedMessage message)
{
var properties = new
{
MessageType = message.Headers["NServiceBus.EnclosedMessageTypes"],
MessageId = message.Headers["NServiceBus.MessageId"],
OriginatingMachine = message.Headers["NServiceBus.OriginatingMachine"],
OriginatingEndpoint = message.Headers["NServiceBus.OriginatingEndpoint"],
ExceptionType = message.Headers["NServiceBus.ExceptionInfo.ExceptionType"],
ExceptionMessage = message.Headers["NServiceBus.ExceptionInfo.Message"],
ExceptionSource = message.Headers["NServiceBus.ExceptionInfo.Source"],
TimeSent = message.Headers["NServiceBus.TimeSent"]
};
_logger.Error("Message sent to error queue. " + properties, message.Exception);
}
}
The observable is implemented by using Reactive Extensions, so you will have to install the NuGet package Rx-Core for this to work.
Could you maybe use a custom log4net configuration to do it?
http://help.airbrake.io/discussions/suggestions/157-net-plug-in-for-api-v2
There is an interface in NServiceBus called IManageMessageFailures, but I don't believe you can use it in conjucntion with the Second Level Retries so you would probably lose that if you did go for your own.
You could write the errors to SQL Server with log4net and the from there you could forward them to AirBrake using their API marking each error in the error table as sent afterwards maybe?
We switched to Serilog, it has perfect logging ans tracing support for NServiceBus. Creating a custom Serilog sink that will send your log events wherever you want is quite easy.
I would suggest that you create a custom endpoint that feeds off the error queue and uploads the data to AirBrake.
Side note: v4.0|4.1 will come with a nice Rest-Api that gives you nice management/querying capabilities for the errors. Tools like the Profiler and Ops will use this api to present the data to you in various ways.
http://particular.net/service-platform