I have a Java ee 7 JMS app, I would like deploy it on CloudBees. I have tried a simple app with cloudAMQP, it work. But CloudAMQP offers hosted RabbitMQ service. I have to use JMS client, because my code is implement in java JMS.
The last day, I have create a glassfish 4 broker in Amazon Ec2, I have deployed a simple JMS app in CloudBees glassfish web profile platform and I have expected it can work with my Amazon glassfish broker. But there is a error.
My code is:
#JMSConnectionFactoryDefinition(
name="java:comp/jms/__defaultConnectionFactory",
maxPoolSize = 30,
minPoolSize= 20,
properties = {
"addressList=mq://ec2-54-194-27-99.eu-west-1.compute.amazonaws.com:7676",
"reconnectEnabled=true"
}
)
#JMSDestinationDefinition(
name = "java:comp/jms/webappQueue",
interfaceName = "javax.jms.Queue",
destinationName = "PhysicalWebappQueue")
#Named
#RequestScoped
public class ReceiverBean {
static final Logger logger = Logger.getLogger("ReceiverBean");
#Inject
private JMSContext context;
#Resource(lookup = "java:comp/jms/webappQueue")
private Queue queue;
.....
public void getMessage() {
try {
JMSConsumer receiver = context.createConsumer(queue);
String text = receiver.receiveBody(String.class, 1000);
if (text != null) {
FacesMessage facesMessage =
new FacesMessage("Reading message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} else {
FacesMessage facesMessage =
new FacesMessage("No message received after 1 second");
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
}
} catch (JMSRuntimeException t) {
logger.log(Level.SEVERE,
"ReceiverBean.getMessage: Exception: {0}",
t.toString());
}
}
The error is
|2013-11-17T22:34:09.146+0000|SEVERE|glassfish 4.0|javax.enterprise.system.core|_ThreadID=45;_ThreadName=AutoDeployer;_TimeMillis=1384727649146;_LevelValue=1000;|
Exception while loading the app : CDI deployment failure:Exception
List with 2 exceptions:
Exception 0 :
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied
dependencies for type [JMSContext] with qualifiers [#Default] at
injection point [[BackedAnnotatedField] #Inject private
javaeetutorial.websimplemessage.SenderBean.context]
Can you have some ideas for my case?
Thanks in advance.
Web profile don't include JMS, so this API and related annotation / injection isn't supported.
For this to work you need a full-profile JavaEE + adequate configuration set in container to plug your broker. Probably simpler to use vanila JMS API vs annotation-driven integration
Related
There are two microservices deployed with docker compose. A dependecy between services is defined in docker compose file by depends_on property. Is it possible to achieve the same effect implicitly, inside the spring boot application?
Let's say the microservice 1 depends on microservice 2. Which means, microsearvice 1 doesn't boot up before microservice 2 is healthy or registered on Eureka server.
By doing some research, I found a solution to the problem.
Spring Retry resolves dependency on Spring Cloud Config Server. Maven dependency spring-retry should be added into the pom.xml, and the properties below into the .properties file:
spring.cloud.config.fail-fast=true
spring.cloud.config.retry.max-interval=2000
spring.cloud.config.retry.max-attempts=10
The following configuration class is used to resolve dependency on other microservices.
#Configuration
#ConfigurationProperties(prefix = "depends-on")
#Data
#Log
public class DependsOnConfig {
private List<String> services;
private Integer periodMs = 2000;
private Integer maxAttempts = 20;
#Autowired
private EurekaClient eurekaClient;
#Bean
public void dependentServicesRegisteredToEureka() throws Exception {
if (services == null || services.isEmpty()) {
log.info("No dependent services defined.");
return;
}
log.info("Checking if dependent services are registered to eureka.");
int attempts = 0;
while (!services.isEmpty()) {
services.removeIf(this::checkIfServiceIsRegistered);
TimeUnit.MILLISECONDS.sleep(periodMs);
if (maxAttempts.intValue() == ++attempts)
throw new Exception("Max attempts exceeded.");
}
}
private boolean checkIfServiceIsRegistered(String service) {
try {
eurekaClient.getNextServerFromEureka(service, false);
log.info(service + " - registered.");
return true;
} catch (Exception e) {
log.info(service + " - not registered yet.");
return false;
}
}
}
A list of services that the current microservice depends on are defined in .properties file:
depends-on.services[0]=service-id-1
depends-on.services[1]=service-id-2
A bean dependentServicesRegisteredToEureka is not being initialized until all services from the list register to Eureka. If needed, annotation #DependsOn("dependentServicesRegisteredToEureka") can be added to beans or components to prevent attempting an initialization before dependentServicesRegisteredToEureka initialize.
I am using wildfly jms queue... I'm using wildfly 9.0.2.Final
I make the producer like this :
#Inject
private JMSContext jmsContext;
private JMSProducer jmsProducer;
#Resource(mappedName = "java:/jboss/exported/jms/queue/TosDownloadReport")
private Queue queueDownloadReport;
public void downloadReport(String adminId, DownloadReportFilter filter){
try {
jmsProducer = jmsContext.createProducer();
String requestParam = Json.getInstance().getObjectMapper().writeValueAsString(filter);
LOG.info("requestParam {}", requestParam);
String id = UUID.randomUUID().toString().replace("-", "");
RoutingRequest request = new RoutingRequest();
request.putProperty("id", id);
request.putProperty("adminId", adminId);
request.putProperty("parameterRequest", requestParam);
QueueMsgDownloadReport message = new QueueMsgDownloadReport();
message.setId(id);
message.setAdminId(adminId);
String jsonMsg = Json.getInstance().getObjectMapper().writeValueAsString(message);
gatewayService.send(RESOURCE, METHOD, request);
jmsProducer.send(queueDownloadReport, jsonMsg);
} catch (Exception e) {
LOG.error(e.getMessage(),e);
}
}
But sometimes i get exception like this and i must restart wildfly
2017-05-05 11:08:20,004 ERROR [com.daksa.tos.infrastructure.api.TosTimer] (EJB default - 7) Could not create a session: IJ000453: Unable to get managed connection for java:/JmsXA: javax.jms.JMSRuntimeException: Could not create a session: IJ000453: Unable to get managed connection for java:/JmsXA
Caused by: javax.resource.ResourceException: IJ000655: No managed connections available within configured blocking timeout (30000 [ms])
From what i read, i don't need to call jmsContext.close() if i'm using inject right?
Please tell me what i do wrong...Thx
CloudBees is add a new Java EE 7/Glassfish 4 Full plateform in their clickstart. If I understand correctly, this mean that it support all Java EE 7 features(contain JMS app). But when I run my JMS app, it log a error "Failed to obtain/create connection from connection pool [ jms/__defaultConnectionFactory-Connection-Pool"
This is my code, it work in my localhost:
#Named
#RequestScoped
public class ReceiverBean {
static final Logger logger = Logger.getLogger("ReceiverBean");
#Inject
private JMSContext context;
#Resource(lookup = "java:comp/jms/webappQueue")
private Queue queue;
.....
public void getMessage() {
try {
JMSConsumer receiver = context.createConsumer(queue);
String text = receiver.receiveBody(String.class, 1000);
if (text != null) {
FacesMessage facesMessage =
new FacesMessage("Reading message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} else {
FacesMessage facesMessage =
new FacesMessage("No message received after 1 second");
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
}
} catch (JMSRuntimeException t) {
logger.log(Level.SEVERE,
"ReceiverBean.getMessage: Exception: {0}",
t.toString());
}
}
The log of glassfish in CloudBees console:
[#|2013-11-19T07:36:43.737+0000|INFO|glassfish
4.0|javax.enterprise.resource.jms.com.sun.enterprise.connectors.jms.system|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846603737;_LevelValue=800;_MessageID=addresslist.setjmsservice.provider;|
JMS010: ADDRESSLIST in setJmsServiceProvider: mq://localhost:0/|#]
[#|2013-11-19T07:36:43.738+0000|INFO|glassfish
4.0|javax.enterprise.resource.jms.com.sun.enterprise.connectors.jms.system|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846603738;_LevelValue=800;_MessageID=jms.connection.url;|
JMS08: JMS Service Connection URL is : mq://localhost:0/|#]
[#|2013-11-19T07:36:44.552+0000|INFO|glassfish
4.0|javax.resourceadapter.mqjmsra.lifecycle|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846604552;_LevelValue=800;|
MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter: Version: 5.0
(Build 14-e) Compile: April 12 2013 0104|#]
[#|2013-11-19T07:36:44.559+0000|INFO|glassfish
4.0|javax.resourceadapter.mqjmsra.lifecycle|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846604559;_LevelValue=800;|
MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter starting: broker is
EMBEDDED, connection mode is Direct|#]
[#|2013-11-19T07:36:44.847+0000|INFO|glassfish
4.0|imq.log.Logger|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846604847;_LevelValue=800;|
[B1002]: An existing property file for imqbroker was not found, no
stored properties will be loaded |#]
[#|2013-11-19T07:36:45.558+0000|SEVERE|glassfish
4.0||_ThreadID=21;_ThreadName=Thread-4;_TimeMillis=1384846605558;_LevelValue=1000;|
Broker exiting.|#]
[#|2013-11-19T07:36:45.562+0000|INFO|glassfish
4.0|javax.resourceadapter.mqjmsra.lifecycle|_ThreadID=21;_ThreadName=http-listener-1(1);_TimeMillis=1384846605562;_LevelValue=800;|
MQJMSRA_RA1101: GlassFish MQ JMS Resource Adapter Started:EMBEDDED|#]
[#|2013-11-19T07:36:49.808+0000|WARNING|glassfish
4.0|javax.enterprise.resource.resourceadapter.com.sun.enterprise.connectors|_ThreadID=22;_ThreadName=http-listener-1(2);_TimeMillis=1384846609808;_LevelValue=900;_MessageID=poolmgr.get_connection_failure;|
RAR5117 : Failed to obtain/create connection from connection pool [
jms/__defaultConnectionFactory-Connection-Pool ]. Reason :
com.sun.appserv.connectors.internal.api.PoolingException|#]
[#|2013-11-19T07:36:49.811+0000|SEVERE|glassfish
4.0|SenderBean|_ThreadID=22;_ThreadName=http-listener-1(2);_TimeMillis=1384846609811;_LevelValue=1000;|
SenderBean.sendMessage: Exception:
com.sun.messaging.jms.MQRuntimeException: MQRA:DCF:allocation
failure:createConnection:Error in allocating a connection. Cause:
null|#]
Anyone could tell me why?
Many thanks in advance
CloudBees supports the web profile on the Glassfish stack, see here. JMS is only supported on the full profile, see here.
You can try the Glassfish 3 full profile here. It is a community stack.
"Glassfish 4 Full Profile" clickstack is a work in progress, it doesn't support JMS yet, neither does it support distributed EJB or comparable JavaEE stuff.
I am new to JMS and have an issue connecting to a remote JMS queue from my standalone client. Any hints on resolving this issue would be highly appreciated.
Right now I have a JavaFX standalone application that runs on multiple clients and a glassfish server 3.1.2.2 running on a remote Unix machine. I am having a hard time pushing messages from my standalone app on to the queue that is residing on the server.
Client Mc: Windows PC (No server installed)
Remote Mc: Unix (GlassFish 3.1.2.2 installed)
JMS resources on the server:
JMS Destination Resource
JNDI Name: jms/ReferralQueue
Physical Destination Name: ReferralQueue
Resource Type: javax.jms.Queue
JMS Connection Factory
Pool Name: jms/ReferralConnectionFactory
JNDI Name: jms/ReferralConnectionFactory
Resource Type: javax.jms.QueueConnectionFactory
JMS Service Type: Embedded
JMS Message Store Type: File
Client Side Code to connect to the server:
jms.properties:
org.omg.CORBA.ORBInitialHost=UNIX MC URL
org.omg.CORBA.ORBInitialPort=7676
Service Locator design to implement resource caching
public class JMSServiceLocator {
private static JMSServiceLocator singletonService = null;
private static QueueConnectionFactory qFactory;
private static Queue queue;
private InitialContext context;
private static Properties properties = new Properties();
private Map cache;
static {
try {
singletonService = new JMSServiceLocator();
} catch (Exception e) {
//error handling
}
}
private JMSServiceLocator() {
try {
loadProperties();
context = new InitialContext(properties);
cache = Collections.synchronizedMap(new HashMap());
} catch (Exception e) {
//error handling
}
}
public static JMSServiceLocator getInstance() {
return singletonService;
}
public QueueConnectionFactory getQueueConnectionFactory() {
String qConnFactoryName = "jms/ReferralConnectionFactory";
qFactory = null;
try {
System.out.println("/********************Comment after Testing*****************************/");
Hashtable env = context.getEnvironment();
System.out.println("**env.size::" + env.size());
Enumeration names = env.keys();
while (names.hasMoreElements()) {
String str = (String) names.nextElement();
System.out.println("**" + str + "=" + env.get(str));
}
System.out.println("/**********************************************************************/");
if (cache.containsKey(qConnFactoryName)) {
qFactory = (QueueConnectionFactory) cache.get(qConnFactoryName);
} else {
qFactory = (QueueConnectionFactory) context.lookup(qConnFactoryName);
cache.put(qConnFactoryName, qFactory);
}
} catch (Exception e) {
//error handling
}
return qFactory;
}
public Queue getQueue() {
String queueName = "jms/ReferralQueue";
queue = null;
try {
if (cache.containsKey(queueName)) {
queue = (Queue) cache.get(queueName);
} else {
queue = (Queue) context.lookup(queueName);
cache.put(queueName, queue);
}
} catch (Exception e) {
//error handling
}
return queue;
}
private static void loadProperties() {
//Load jms properties
}
}
Eventually sending message to the server:
JMSServiceLocator jmsLocator = JMSServiceLocator.getInstance();
QueueConnectionFactory qConnFactory = jmsLocator.getQueueConnectionFactory();
qConnection = qConnFactory.createQueueConnection();
session = qConnection.createSession(false, ession.AUTO_ACKNOWLEDGE);
queue = jmsLocator.getQueue();
// Push and publish the message
messageProducer = session.createProducer(queue);
textMessage = session.createTextMessage();
textMessage.setText(message);
messageProducer.send(textMessage);
Hmmm... Now I observe a strange behavior...
I created a new GlassFish 3.1.2.2 server instance on the client machine with no jndi, no connection factories, and no jms queues what so ever.
I have started this server instance and executed the standalone client application. Strangely, everything works fine and the message is directly being pushed to the remote queue.
Did any one come across this kind of issue? I am suspecting that probably the application is loading the dependent GlassFish jars in the classpath only when a server instance (could be any random instance, totally unrelated) is started.
I have the following jars in my standalone application classpath:
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\gf-client.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\appserv-rt.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\install\applications\jmsra\imqbroker.jar
*C:\Program Files\glassfish-3.1.2.2\glassfish\lib\install\applications\jmsra\imqjmsra.jar
I have also posted this on Oracle JMS and GlassFish forums and haven't got a solution. Any help on this issue would be highly appreciated.
Thanks.
I think you found out by now what the problem was:
the JMS client jars were missing on the client (Client Mc: Windows PC (No server installed)).
You don't need a full Glassfish installation on the clients but only the JMS client jars (gf-client.jar) plus all the other jars referenced by gf-client.jar.
I am using Spring amqp 1.1 version as my java client.
I have a queue which has around 2000 messages. I want to have a service which checks this queue size and and if it is empty it will send out a message saying " All items processed".
I dont know how to get current queue size ? Please help
I googled and found a class "RabbitBrokerAdmin" that was present in earlier version 1.0.
I think it is not present in 1.1 now.
Any pointers in getting current queue size?
So I know this is a little late and a solution has already been found but here is another way to look message counts in your queues
This solution assumes that you are using the spring rabbitmq framework and have defined your queues in your application config with the following tags defined
<rabbit:queue>
<rabbit:admin>
The java class:
public class QueueStatsProcessor {
#Autowired
private RabbitAdmin admin;
#Autowired
private List<Queue> rabbitQueues;
public void getCounts(){
Properties props;
Integer messageCount;
for(Queue queue : rabbitQueues){
props = admin.getQueueProperties(queue.getName());
messageCount = Integer.parseInt(props.get("QUEUE_MESSAGE_COUNT").toString());
System.out.println(queue.getName() + " has " + messageCount + " messages");
}
}
}
You can also use this solution to read the current consumers attached to the queue
http://docs.spring.io/spring-amqp/docs/1.2.1.RELEASE/api/org/springframework/amqp/rabbit/core/RabbitAdmin.html#getQueueProperties(java.lang.String)
You can use the RabbitAdmin instance to get the details from the queue, as follows:
#Resource RabbitAdmin admin;
...
protected int getQueueCount(final String name) {
DeclareOk declareOk = admin.getRabbitTemplate().execute(new ChannelCallback<DeclareOk>() {
public DeclareOk doInRabbit(Channel channel) throws Exception {
return channel.queueDeclarePassive(name);
}
});
return declareOk.getMessageCount();
}