Azure Functions Java using ServiceBusQueueOutput to send message with schedule enqueue time - java

message send to the servicebus can be processed by consumer after some time, simply by setting ScheduledEnqueueTime param.
Its easy to achieve this while working on "raw" service bus message ie:
var serviceBusMessage = new ServiceBusMessage(json);
serviceBusMessage.setScheduledEnqueueTime(someTime);
but I have azure functions java app, that has:
#FunctionName("Process-Notifications")
public void processNotifications(
#ServiceBusQueueTrigger(name = "MessageCmd", queueName = "queue_name_notify_cmd_v1", connection = "SBusConn") String messageCmd,
#ServiceBusQueueOutput(name = "NotifyForRetry", queueName = "queue_name_notify_cmd__v1", connection = "SBusConn") OutputBinding<String> notifyForRetry,
sending notification is easy here, I only do:
Map<String, Object> result = mapper.convertValue(json, new TypeReference<>() {
});
String channels = "";
if (error instanceof SmsOnlyError) {
channels+="sms";
}
if (error instanceof EmailOnlyError) {
channels+="email";
}
if (error instanceof AllDefinedChannelsError) {
channels+="sms, email";
}
properties.put("retry_channels", channels);
result.put("UserProperties", properties);
result.put("ScheduledEnqueueTime", OffsetDateTime.now(defaultClock).plusMinutes(15).toString());
JsonNode newJson = mapper.convertValue(result, JsonNode.class);
hard to find something in docs, maybe someone here can me ?
thanks!
and works fine. But I have no idea how to set ScheduledEnqueueTime there..

Unfortunately, this isn't currently supported by non-C# languages in Azure Functions. You would have to use the Azure SDK for Service Bus directly in your code.

Related

asynchronous java method on service layer

I'm using a library called PubNub for posting messages. The PubNub method posts messages asynchronously, and it has a way to see if the message was posted or not.
I'm using Spring MVC and ThymeLeaf, so I would like to send the response back to my front-end after I get the message status (error or success), however, I don't know how to wait until my PubNub method finishes, and then send the result. Here's the code:
#Controller
public class HomeController {
#PostMapping("/triggerDevices")
public String triggerDevices(#ModelAttribute(value = "message") Message message, Model model) {
//
//
// validations and build data
//
//
MyResult result = null;
//Async method
pubNub.publish()
.message(message)
.channel(channel)
.async((result, status) -> {
//This block takes some time
if (status == null || status.isError()) {
//Error case
result = new MyResult (false, status.errorMessage(),message.device);
} else {
//Success case
result = new MyResult (true, null, message.device);
}
});
//Result
model.addAttribute("result", result);
return "home :: info-success";
}
}
I hope someone helps me, thanks so much.
PubNub Java SDK Publish sync
Just use the sync method instead of async
PNPublishResult result = pubnub.publish()
.channel("coolChannel")
.message("test")
.shouldStore(true)
.ttl(10)
.sync();
See full PubNub SDK Java Docs for publish/sync.
That should do it for you.
Cheers!
Using sync is an easy fix! but if u need to keep it async, i would return within the async function result here after you get the result:
//Success case
result = new MyResult (true, null, message.device);
model.addAttribute("result", result);
return "home :: info-success";

In java with azure function #ServiceBusQueueTrigger, how to get the Label, Custom Properties and Broker Properties?

This is the azure web page example in JAVA to get the message content from the azure service bus :
#FunctionName("sbprocessor")
public void serviceBusProcess(
#ServiceBusQueueTrigger(name = "msg",
queueName = "myqueuename",
connection = "myconnvarname") String message,
final ExecutionContext context
) {
context.getLogger().info(message);
}
This only return the content of the message. How is it possible to get the other fields that you can see in Service bus explorer : Label, Custom Properties and Broker Properties ?
You can retrieve message metadata by adding #BindingName("UserProperties") etc. annotation to method parameters like below for example. You can bind to any metadata of a message using binding expression. In this case below, it's "Properties" and "Label".
#FunctionName("sbprocessor")
public void serviceBusProcess(
#ServiceBusQueueTrigger(name = "msg", queueName = "myqueuename", connection = "myconnvarname")
String message,
final ExecutionContext context,
#BindingName("UserProperties")
Map<String, Object> properties,
#BindingName("Label")
String label) {
context.getLogger().info("Message received: " + message + " , properties: " + properties + " , label: " + label);
}
I used Service Bus Explorer as Message Sender to set metadata of the message as below and was able to see those in the consumer side using above code in "UserProperties" binding.
N.B. C# function SDK has a benefit here over Java. In C#, you can get the whole BrokeredMessage object which is easier to navigate for metadata directly. But unfortunately, that's not possible in Java SDK as of now where you have to bind separately.

Spring Boot Thymeleaf JavaMail -"class path resource [images/logo.png] cannot be opened because it does not exist " with streams.foreach

I am using Spring Boot and Thymeleaf to send emails. I have one inline image as a signature in the email. Everything works fine if I send one email at a time. But, my use case is to send an individual email to a list of recipients. I am able to do that without the image. But, when I add the image, the first email is getting sent and for the second time I get class path resource [images/tp-logo.png] cannot be opened because it does not exist.
When I call emailService.send() from the stream.forEach() I get above error.
When I call it from a normal for loop, it works fine.
I understand that the streams are lazy, but why the resource is missing?
Working Caller method code:
for(ContactIfo contact : contactInfoList) {
ExecutorService emailExecutor = Executors.newCachedThreadPool();
emailExecutor.execute(() -> {
final String emailAddress = contact.getEmailAddress();
if (StringUtils.isNotBlank(emailAddress)) {
emailService.sendEmail(emailAddress);
}
});
}
Failing caller method code:
contactInfoList.parallelStream().forEach(contact -> {
ExecutorService emailExecutor = Executors.newCachedThreadPool();
emailExecutor.execute(() -> {
final String emailAddress = contact.getEmailAddress();
if (StringUtils.isNotBlank(emailAddress)) {
emailService.sendEmail(emailAddress);
}
});
});
Callee:
private void sendEmail(Mail mail) throws MessagingException {
MimeMessage message = emailSender.createMimeMessage();
MimeMessageHelper helper = new MimeMessageHelper(message,
MimeMessageHelper.MULTIPART_MODE_MIXED_RELATED,
StandardCharsets.UTF_8.name());
Context context = new Context();
context.setVariables(mail.getProps());
String html = templateEngine.process("me-event-update-template", context);
helper.setText(html , true);
helper.setTo(mail.getMailTo());
helper.setSubject(mail.getSubject());
helper.setFrom(mail.getFrom());
// adding inline resources with matching cId to the variable name/value
helper.addInline("logo", new ClassPathResource("images/logo.png"), "image/png");
emailSender.send(message);
}

How can i add extra key in UrbanAirship API using java

I am sending push notifications using UrbanAirship API using java.
Here is the doc: http://docs.urbanairship.com/api/
I want to send a push notifications with custom key/value. For example, I want send to following to Android/iOS device
name: "Jack"
String appKey = "appKey";
String appSecret = "appSecret";
// Setup an authenticated APIClient with your application key and
// application master secret.
APIClient apiClient = APIClient.newBuilder()
.setKey(appKey)
.setSecret(appSecret)
.build();
// Setup a push payload to send to the API with our handy builders
PushPayload payload = PushPayload.newBuilder()
.setAudience(Selectors.all())
.setNotification(Notifications.notification("UA Push"))
.setDeviceTypes(DeviceTypeData.of(DeviceType.IOS))
.build();
// Try and send, handle anything that comes up
try {
APIClientResponse<APIPushResponse> response = apiClient.push(payload);
logger.info("Sent a push message!");
}
// Non 200 responses throw an APIRequestException. Check the documentation
// to debug your request.
catch (APIRequestException ex){
logger.error("Non 200 request, checking error details and taking action");
}
// An underlying error occurred, most likely outside of the scope of the
// UA library, do some HTTP debugging
catch (IOException e){
logger.error("Broken pipe what?");
}
Here is the code reference for android - https://github.com/urbanairship/java-library/blob/master/src/test/java/com/urbanairship/api/push/model/notification/android/AndroidDevicePayloadTest.java
How can i do send push notification with custom key/value using AndroidDevicePayload ?
You can create your notification like this:
public PushPayload createPushPayloadCustom(String namedUser, String message) {
Notification notification = Notification.newBuilder()
.addDeviceTypeOverride(DeviceType.IOS, IOSDevicePayload.newBuilder()
.setAlert(message)
.build())
.addDeviceTypeOverride(DeviceType.ANDROID, AndroidDevicePayload.newBuilder()
.setAlert(message)
.build())
.build();
return PushPayload.newBuilder()
.setAudience(Selectors.namedUser(namedUser))
.setNotification(notification)
.setDeviceTypes(DeviceTypeData.of(DeviceType.ANDROID, DeviceType.IOS))
.build();
}
You can add to the "extras" object any key/value:
DeviceTypeData deviceTypeData = DeviceTypeData.of(DeviceType.IOS, DeviceType.ANDROID);
IOSDevicePayload iosPayload = IOSDevicePayload.newBuilder()
.setAlert(message)
.addExtraEntry("custom_ios_key", "custom value for IOS")
.build();
AndroidDevicePayload androidPayload = AndroidDevicePayload.newBuilder()
.setAlert(message)
.addExtraEntry("custom_android_key", "custom value for Android")
.build();
PushPayload payload = PushPayload.newBuilder()
.setAudience(Selectors.namedUser(email))
.setNotification(Notifications.notification(iosPayload,androidPayload))
.setDeviceTypes(deviceTypeData)
.build();
Then in the received push, you will find the object:
For more details go to urbanairship official documentation

Java : Using Spring remoting for getting objects from server

I am working on a JavaSE application in which I would like to connect to a Spring-MVC based server to get List of objects, Objects itself. I looked up on net, and came upon JSON. While I agree that it is working, but it is very inefficient as I have to go through the 2 while loops and seems not so sophisticated. For this reason I researched and found out I can use Spring remoting to achieve the task.
One thing I would like to do is to send over objects directly, instead of converting them by JSON, and sending.
I am pasting my code below for what I have with JSON, I would appreciate if I know this seems more better or is Spring remoting more sophisticated in long term too. A replacement code for the client side would be nice. Thanks.
Client code :
public void getCanvas(){
JsonFactory jsonFactory = new JsonFactory();
String canvas = "";
try {
JsonParser jsonParser = jsonFactory.createJsonParser(new URL(canvasURL));
JsonToken token = jsonParser.nextToken();
while (token!=JsonToken.START_ARRAY && token!=null){
token = jsonParser.nextToken();
if(token==null){break;}
System.out.println("Token is "+jsonParser.getText());
}
while (token!=JsonToken.END_ARRAY){
token = jsonParser.nextToken();
if(token == JsonToken.START_OBJECT){
canvas = jsonParser.toString();
System.out.println("Canvas is "+canvas);
}
}
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("Canvas is "+canvas);
}
Server code :
#RequestMapping(value = "/getcanvas",method = RequestMethod.GET)
public #ResponseBody String getCanvasforFX(){
System.out.println("Canvas was requested");
Canvas canvas = this.canvasService.getCanvasById(10650);
canvas.setCanvasimage(null);
ObjectMapper objectMapper = new ObjectMapper();
try {
System.out.println("Canvas value is "+objectMapper.writeValueAsString(canvas));
return objectMapper.writeValueAsString(canvas);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
In the client-code I am getting the information, but again I have to read the fields, set them in object and update the UI, even though I am programming the server also, I want to directly receive an object, and cut out the middle-man(JSON). Thanks.

Categories