Generate Client ID on deploy - jms

I have a WildFly cluster which should share all topic messages to different nodes and keep them if one node is offline.
For this case I need durable subscriper.
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/Topic"),
#ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
#ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "anam123e"),
#ActivationConfigProperty(propertyName = "clientID", propertyValue = "abcd"),
}
)
I have noticed if I am using the same clientID the system is doing load-balancing. If I change the clientID or subscriptionName to an unique value it works.
So when to use a unique clientID and when subscriptionName?
My answer was, unique clientID per Node and subscriptionName per Thread on a Node.
Furthermore I want to generate a clientID based on the wildfly node name similar to:
#ActivationConfigProperty(propertyName = "clientID", propertyValue = "abcd-" + WildFly.getInstance().getNodeName()),
Is there a way to achieve it?

There is a real simple solution available: Property Replacement
You need to enable it in the standalone.xml:
<subsystem xmlns="urn:jboss:domain:ee:2.0">
<annotation-property-replacement>true</annotation-property-replacement>
...
</subsystem>
And the new annotation can look like the following:
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "jms/Topic"),
#ActivationConfigProperty(propertyName = "subscriptionDurability", propertyValue = "Durable"),
#ActivationConfigProperty(propertyName = "subscriptionName", propertyValue = "aname"),
#ActivationConfigProperty(propertyName = "clientID", propertyValue = "abcd-${jboss.node.name}"),
}
)

Related

How to make an MDB consume sequentially in WildFly

I'm following this article to create a JMS message listener. Everything run correctly. When a producer sends a message the listener can recognize the new message and start doing something.
However, when the producer publishes multiple messages at the same time, the listener also handles these messages concurrently. How can I make the listener run sequentially? I want it to handle the next message only when the previous message is handled successfully.
This my my MessageListener:
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destination", propertyValue = "SendingSMSQueue"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")
})
public class SendgridEmail2SmsMessageListener implements MessageListener {
#Override
public void onMessage(Message message) {
try {
log.info("Receive {}", message);
// Do some heavy things
Thread.sleep(2000);
log.info("Finish");
} catch (Exception e) {
log.error("Listen message sending SMS failed", e);
}
}
}
After hours of research, I found that there is an ActivationConfigProperty that allow us define the maximum sessions can handle our request, so in my case, I just need to set maxSession is 1 like this:
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "destination", propertyValue = "SendingSMSQueue"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "maxSession", propertyValue = "1")
})
public class SendgridEmail2SmsMessageListener implements MessageListener {
For more information, let reference this page https://docs.jboss.org/ejb3/docs/tutorial/1.0.7/html/Message_Driven_Beans.html

IllegalArgumentException configuring MDB in weblogic12 using annotations

My MDB code:
#MessageDriven(name="FOOListener",activationConfig = {
#ActivationConfigProperty(propertyName = "initial-context-factory", propertyValue = "com.sun.jndi.fscontext.RefFSContextFactory"),
#ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue = "someJndiName"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destinationJndiName", propertyValue = "a.b.c.queue")})
public class PaymentAdviceMessageListener implements MessageListener{
private MessageDrivenContext mdContext = null;
#Override
public void setMessageDrivenContext(MessageDrivenContext mdc) throws EJBException {
logger.log(Severity.INFO,"setMessageDrivenContext()", this.getClass().getName());
mdContext = mdc;
}
#Override
public void onMessage(Message jmsMessage) {
....
When I start weblogic server, I get following exception:
<MessageDrivenBean threw an Exception in onMessage(). The exception is:
java.lang.IllegalArgumentException: Can not set javax.ejb.MessageDrivenContext field com.abc.fc.xxx.webservice.mq.PaymentAdviceMessageListener.mdctx to weblogic.jndi.internal.WLEventContextImpl.
java.lang.IllegalArgumentException: Can not set javax.ejb.MessageDrivenContext field com.abc.fc.xxx.webservice.mq.PaymentAdviceMessageListener.mdctx to weblogic.jndi.internal.WLEventContextImpl
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at org.jboss.weld.introspector.jlr.WeldFieldImpl.set(WeldFieldImpl.java:88)
at org.jboss.weld.injection.FieldInjectionPoint.inject(FieldInjectionPoint.java:136)
at org.jboss.weld.util.Beans.injectEEFields(Beans.java:629)
at org.jboss.weld.manager.SimpleInjectionTarget$1.proceed(SimpleInjectionTarget.java:106)
at com.oracle.injection.provider.weld.WeldInjectionServicesAdapter.aroundInject(WeldInjectionServicesAdapter.java:89)
at org.jboss.weld.injection.InjectionContextImpl.run(InjectionContextImpl.java:45)
It works fine with EJB2 style depolyment descriptors. I need it to work using annotations. Please help.

upload file using rest services in spring mvc

I want to upload a file( any type of file ) into a forlder using web services and spring mvc so I have a sever side and a client side.
On my client side this is the code
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST , produces="application/json")
public #ResponseBody
Boolean uploadMultipleFileHandler(
#RequestParam("name") MultipartFile[] files) {
MailService ms= new MailService();
Map<String, List<ByteArrayResource>>rval = new HashMap<String, List<ByteArrayResource>>();
String message = "";
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
List<Object> files1 = new ArrayList<>();
List<Object> files2 = new ArrayList<>();
for (int i = 0; i < files.length; i++) {
MultipartFile file = files[i];
System.out.println(file.getOriginalFilename());
try {
byte[] bytes = file.getBytes();
files1.add(new ByteArrayResource(bytes));
files2.add(file.getOriginalFilename());
//System.out.println(map.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
map.put("files", files1);
map.put("names", files2);
System.out.println(map.get("files").toString());
RestTemplate restTemplate = new RestTemplate();
String SERVER_URI="http://localhost:8080/BackEndFinalVersion";
Boolean p=restTemplate.postForObject(SERVER_URI+"/uploadMultipleFile", map, Boolean.class);
System.out.println(p.toString());
//message = message + ms.encodeFileToBase64Binary( bytes);
//rval.put("success",message);
return true;
}
and the server side code is
#RequestMapping(value = "/uploadMultipleFile", method = RequestMethod.POST, produces = "application/json")
public #ResponseBody Boolean uploadMultipleFileHandler(#RequestParam("files") List<Object> files , #RequestParam("names") List<Object> names) {
//MailService ms= new MailService();
//Map<String, Object> rval = new HashMap<String, Object>();
String message = "";
System.out.println("looool");
System.out.println(files);
System.out.println(names);
//System.out.println(files.get(0).toString());
for (int i = 0; i < files.size(); i++) {
System.out.println(files.get(i).getClass());
String file = (String)files.get(i);
try {
byte[] bytes = file.getBytes();
//FileUtils.writeStringToFile(new File("log.txt"), file, Charset.defaultCharset());
// Creating the directory to store file
String rootPath = "C:/Users/Wassim/Desktop/uploads";
File dir = new File(rootPath);
if (!dir.exists())
dir.mkdirs();
File serverFile = new File(dir.getAbsolutePath() + File.separator + ( names.get(i)));
BufferedOutputStream stream = new BufferedOutputStream(new FileOutputStream(serverFile));
stream.write(bytes);
stream.close();
//message = message + "You successfully uploaded file=" + ( (MultipartFile) files.get(i)).getOriginalFilename() + "<br />";
//FileUtils.writeByteArrayToFile(new File(dir.getAbsolutePath() + File.separator + files.get(i).getOriginalFilename()), ms.decodeFileToBase64Binary(ms.encodeFileToBase64Binary( bytes)));
//rval.put("success"+i, message);
System.out.println("noooo");
} catch (Exception e) {
message += "You failed to upload " + " => " + e.getMessage();
//rval.put("error", message);
return false;
}
}
return true;
My problem is that this code doesn't work only with .txt files
can any one support me ??

wildfly 10, JMS, MDB, topic does not receive message

I have two message driven beans
#MessageDriven(name = "SubscribersTopicQueueMDB", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/topic/Subscribers"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class SubscribersTopicQueueMDB implements MessageListener {
private final static Logger LOGGER = Logger.getLogger(SubscribersTopicQueueMDB.class.toString());
public SubscribersTopicQueueMDB() {
System.out.println("Topic: SubscribersTopicQueueMDB INIT ");
}
and
#MessageDriven(name = "SubscribersTopicSecondMDB", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "jms/topic/Subscriber"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge")})
public class SubscribersTopicSecondMDB implements MessageListener {
private final static Logger LOGGER = Logger.getLogger(SubscribersTopicSecondMDB.class.toString());
public SubscribersTopicSecondMDB() {
System.out.println("TOPIC: SubscribersTopicSecondMDB (Second) INIT ");
}
When i am sending message to topic jms/topic/Subscriber only first MDB is received message, second MDB does not receive any message.
How can i improve this?
my simple client
public static void sendTextMessage(String message, String passedDestination) {
if (message == null || passedDestination == null) {
return;
}
Context namingContext = null;
try {
String userName = JMS_DEFAULT_USERNAME;
String password = JMS_DEFAULT_PASSWORD;
// Set up the namingContext for the JNDI lookup
final Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, JMS_INITIAL_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, JMS_PROVIDER_URL);
// env.put(Context.SECURITY_PRINCIPAL, userName);
// env.put(Context.SECURITY_CREDENTIALS, password);
namingContext = new InitialContext(env);
// Perform the JNDI lookups
String connectionFactoryString = JMS_DEFAULT_CONNECTION_FACTORY;
System.out.println("+##Attempting to acquire connection factory \"" + connectionFactoryString + "\"");
ConnectionFactory connectionFactory = (ConnectionFactory) namingContext.lookup(connectionFactoryString);
System.out.println("+###Found connection factory \"" + connectionFactoryString + "\" in JNDI " + connectionFactory.toString());
String destinationString = passedDestination;
System.out.println("+##Attempting to acquire destination \"" + destinationString + "\"");
Destination destination = (Destination) namingContext.lookup(destinationString);
System.out.println("+###Found destination \"" + destinationString + "\" in JNDI");
int count = 2;
String content = message;
//System.out.println("userName " + userName);
//System.out.println("password " + password);
try (JMSContext context = connectionFactory.createContext()) {
System.out.println("***************Sending to " + destinationString + " messages with content: " + content + " *********************");
context.createProducer().send(destination, content);
}
//return true;
} catch (NamingException e) {
e.printStackTrace();
} finally {
if (namingContext != null) {
try {
namingContext.close();
} catch (NamingException e) {
e.printStackTrace();
}
}
// return false;
}
found my mistake one topic listen jms/topic/Subscriber second jms/topic/Subscribers.improved.

jms publish/subscribe in websphere cluster

I write a publish/subscriber sample and deploy it on websphere application server in cluster environment.
but when I subscribe the message, each message only and only one time was read by MDB.
I configured durable subscription in websphere and MDB, also I set the Share durable subscriptions to always shared and set the Always activate MDBs in all servers.
each message was read only one time, I think it consumes or something else.
I set the #ActivationConfigProperty(propertyName = "useSharedSubscriptionInClusteredContainer",propertyValue = "false") in MDB (based on http://docs.oracle.com/cd/E18930_01/html/821-2438/gjzpg.html#MQAGgjzpg), but nothing happened.
I can not subscribe messages in all servers.
Also i set the messaging engine policy to High availability in the websphere bus.
the Default messaging provider is used.
where is the problem??
here is my publisher
#WebServlet("/publishServlet")
public class Testpublish extends HttpServlet {
#Resource(mappedName = "jms/ConnFact")
private static TopicConnectionFactory topicConnectionFactory;
#Resource(mappedName = "jms/topicJ")
private static Topic topic;
TopicConnection connection = null;
TopicSession session = null;
TopicPublisher publisher = null;
TextMessage message = null;
final int NUM_MSGS = 5;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain");
ServletOutputStream out = response.getOutputStream();
out.println("Start Testing");
System.out.println("Start Testing");
try {
connection = topicConnectionFactory.createTopicConnection();
session = connection.createTopicSession(false, Session.AUTO_ACKNOWLEDGE);
publisher = session.createPublisher(topic);
message = session.createTextMessage();
for (int i = 0; i < NUM_MSGS; i++) {
message.setText("This is testMessage " + (i + 1));
System.out.println("Sending testMessage: " + message.getText());
out.println("Sending testMessage: " + message.getText());
publisher.publish(message);
}
connection.close();
out.println("Finish Testing");
System.out.println("Finish Testing");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
and my subscriber
#MessageDriven(mappedName = "jms/topicJ", activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Topic"),
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "subscriptionDurability",propertyValue = "Durable"),
#ActivationConfigProperty(propertyName = "clientId",propertyValue = "MyID"),
#ActivationConfigProperty(propertyName = "subscriptionName",propertyValue = "MySub")
})
public class testsubscribe implements MessageListener {
#Override
public void onMessage(Message message) {
TextMessage txtMessage = (TextMessage) message;
try {
System.out.println("---------MESSAGE RECIEVED------------" + txtMessage.getText()
+ " ..............");
} catch (JMSException e) {
e.printStackTrace();
}
}
}
I resolved the problem by disabling the messaging engine policy in the websphere bus. Now it works well.

Resources