Unfortunately app has stopped error in notification sending - android-studio

import android.app.NotificationManager;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import com.google.android.gms.gcm.GcmListenerService;
import com.htl.jsfshoppingfestival.DataBaseHandler;
public class MyGcmListenerService extends GcmListenerService {
private static final String TAG = "MyGcmListenerService";
private NotificationManager mNotificationManager;
Context ctx;
int countNotification=0;
public void onMessageReceived(String from, Bundle data) {
String message = data.getString("Message");
Log.d(TAG, "From: " + from);
Log.d(TAG, "Message: " + message);
// Toast.makeText(getApplicationContext(), "Notification :"+message, Toast.LENGTH_LONG).show();
// Toast.makeText(getApplicationContext(),from+message,Toast.LENGTH_LONG).show();
if (from.startsWith("/topics/")) {
// message received from some topic.
} else {
// normal downstream message.
}
// [START_EXCLUDE]
/**
* Production applications would usually process the message here.
* Eg: - Syncing with server.
* - Store message in local database.
* - Update UI.
*/
/**
* In some cases it may be useful to show a notification indicating to the user
* that a message was received.
*/
sendNotification(message);
// [END_EXCLUDE]
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* #param message GCM message received.
*/
private void sendNotification(String message) {
DataBaseHandler db = new DataBaseHandler(this);
db.addMessage(message);
countNotification=db.getRowCount();
db.close();
Log.d("sender", "Broadcasting message");
Intent localIntent = new Intent("badge count");
// You can also include some extra data.
localIntent.putExtra("Count", countNotification);
LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
}
}
I did not get the message as a notification when I send the notification, my app shows:
Unfortunately app has stopped
In debugging I got message=null and app gives error.

In which block you got null? OnMessageReceived or SendNotification?

You need check the message not equal to null.
if(message != null && !message.trim().isEmpty())
{
sendNotification(message);
}

Related

notification sound is not playing in android 10

I am sending notifications through Firebase Cloud Messaging But the sound and vibration are not playing on my phone which has Android 10 but Sound is playing in the android emulator which has android 9. As it is an emulator I can not say it having vibration or not.
I already checked other StackOverflow posts but can not get the solution.
Here is my code-
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
/**
* NOTE: There can only be one service in each app that receives FCM messages. If multiple
* are declared in the Manifest then the first one will be chosen.
* <p>
* In order to make this Java sample functional, you must remove the following from the Kotlin messaging
* service in the AndroidManifest.xml:
* <p>
* <intent-filter>
* <action android:name="com.google.firebase.MESSAGING_EVENT" />
* </intent-filter>
*/
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "MyFirebaseMsgService";
/**
* Called when message is received.
*
* #param remoteMessage Object representing the message received from Firebase Cloud Messaging.
*/
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Log.d(TAG, "From: " + remoteMessage.getFrom());
if (remoteMessage.getData().size() > 0) {
Log.d(TAG, "Message data payload: " + remoteMessage.getData());
}
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
}
}
private void handleNow() {
Log.d(TAG, "Short lived task is done.");
}
private void sendNotification(String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.logo)
.setContentTitle("Brain Filter")
.setColor(getResources().getColor(R.color.colorAccent))
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT);
notificationManager.createNotificationChannel(channel);
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}
I also added Vibration and Internet permission in the manifest.xml and always enable sound in Firebase console when pushing any notification.
Uninstall your app and Install again will fix the issue.
The settings are set the first time you create the channel and then not modified unless you do it manually by fresh install or clearing data.

Receiving messages from Azure IOT Hub using MQTT

I am trying to send messages to Azure IOT hub using MQTT and using Azure Device SDK libraries. There are two devices which are configured on IOT Hub. Both devices have different connection string.
Connection string for device 1
connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=sharedKey";
Connection string for device 2
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=sharedKey";
I have wrote two publishers that will send the messages to IOT hub and the subscriber that will recieve message from IOT Hub sent by the publishers.
In first publisher I have passed connection string for device 1 and for second publisher the connection string for device 2. Now when I am running both the publisher classes simultaneously, subscriber is recieving messages from both the publishers. Can anyone let me know how can I modify the code so that the subscriber will only only recieve messages sent by publisher 1 even when both the publisher are running simultaneously.
Here is my code for Publisher 1.
package com.iot.mqtt.connection;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.gson.Gson;
import com.microsoft.azure.sdk.iot.device.DeviceClient;
import com.microsoft.azure.sdk.iot.device.IotHubClientProtocol;
import com.microsoft.azure.sdk.iot.device.IotHubEventCallback;
import com.microsoft.azure.sdk.iot.device.IotHubStatusCode;
import com.microsoft.azure.sdk.iot.device.Message;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.EventCallback;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.MessageSender;
//import com.microsoft.docs.iothub.samples.SimulatedDevice.TelemetryDataPoint;
public class SimulatedDevice {
// The device connection string to authenticate the device with your IoT hub.
// Using the Azure CLI:
// az iot hub device-identity show-connection-string --hub-name {YourIoTHubName} --device-id MyJavaDevice --output table
private static String connString = "HostName=ABC.azure-devices.net;DeviceId=ABC;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
// Using the MQTT protocol to connect to IoT Hub
private static IotHubClientProtocol protocol = IotHubClientProtocol.MQTT;
private static DeviceClient client;
// Specify the telemetry to send to your IoT hub.
private static class TelemetryDataPoint {
public double temperature;
public double humidity;
public String message;
public String timeStamp;
// Serialize object to JSON format.
public String serialize() {
Gson gson = new Gson();
return gson.toJson(this);
}
}
// Print the acknowledgement received from IoT Hub for the telemetry message sent.
private static class EventCallback implements IotHubEventCallback {
public void execute(IotHubStatusCode status, Object context) {
System.out.println("IoT Hub responded to message with status: " + status.name());
if (context != null) {
synchronized (context) {
context.notify();
}
}
}
}
private static class MessageSender implements Runnable {
public void run() {
try {
// Initialize the simulated telemetry.
double minTemperature = 20;
double minHumidity = 60;
String message;
Random rand = new Random();
InputStream is = null;
Properties prop = null;
prop = new Properties();
is = new FileInputStream("C:\\Users\\H251970\\eclipse-workspace\\IOTMqttTestProject\\resources\\config.properties");
prop.load(is);
message = prop.getProperty("message");
minTemperature = Double.parseDouble(prop.getProperty("temperature"));
minHumidity = Double.parseDouble(prop.getProperty("humidity"));
//System.out.println(message);
while (true) {
// Simulate telemetry.
double currentTemperature = minTemperature + rand.nextDouble() * 15;
double currentHumidity = minHumidity + rand.nextDouble() * 20;
String datatimeStamp= new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(Calendar.getInstance().getTime());;
TelemetryDataPoint telemetryDataPoint = new TelemetryDataPoint();
telemetryDataPoint.temperature = currentTemperature;
telemetryDataPoint.humidity = currentHumidity;
telemetryDataPoint.message = message;
telemetryDataPoint.timeStamp = datatimeStamp;
// Add the telemetry to the message body as JSON.
String msgStr = telemetryDataPoint.serialize();
Message msg = new Message(msgStr);
// Add a custom application property to the message.
// An IoT hub can filter on these properties without access to the message body.
msg.setProperty("temperatureAlert", (currentTemperature > 30) ? "true" : "false");
System.out.println("Sending message: " + msgStr);
Object lockobj = new Object();
// Send the message.
EventCallback callback = new EventCallback();
client.sendEventAsync(msg, callback, lockobj);
synchronized (lockobj) {
lockobj.wait();
}
Thread.sleep(3000);
}
} catch (Exception e) {
System.out.println("Exception: " + e);
} /*finally {
inputStream.close();
}*/
}
}
public static void main(String[] args) throws IOException, URISyntaxException {
// Connect to the IoT hub.
client = new DeviceClient(connString, protocol);
client.open();
// Create new thread and start sending messages
MessageSender sender = new MessageSender();
ExecutorService executor = Executors.newFixedThreadPool(1);
executor.execute(sender);
// Stop the application.
System.out.println("Press ENTER to exit.");
System.in.read();
executor.shutdownNow();
client.closeNow();
}
}
Code for publisher 2 is also same just the connection-string is different.
connString = "HostName=DEF.azure-devices.net;DeviceId=DEF;SharedAccessKey=aTVNu55sN9a2Y9+V0BCAOXdo8nSFDNzByfiTqMvNb20=";
The subscriber is recieving the message in following form.
Sending message: {"temperature":"27.739594911863872°C","voltage":"15.81301816513805V","motorspeed":"5.0m/s","inverterName":"i550","timeStamp":"22/08/2018 11:18:03"}
IoT Hub responded to message with status: OK_EMPTY
Here is the code for Subscriber class
package com.microsoft.docs.iothub.samples;
import com.microsoft.azure.eventhubs.ConnectionStringBuilder;
import com.microsoft.azure.eventhubs.EventData;
import com.microsoft.azure.eventhubs.EventHubClient;
import com.microsoft.azure.eventhubs.EventHubException;
import com.microsoft.azure.eventhubs.EventPosition;
import com.microsoft.azure.eventhubs.EventHubRuntimeInformation;
import com.microsoft.azure.eventhubs.PartitionReceiver;
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.nio.charset.Charset;
import java.net.URI;
import java.net.URISyntaxException;
public class ReadDeviceToCloudMessages {
// az iot hub show --query properties.eventHubEndpoints.events.endpoint --name {your IoT Hub name}
//private static final String eventHubsCompatibleEndpoint = "{your Event Hubs compatible endpoint}";
private static final String eventHubsCompatibleEndpoint = "sb://ihsuprodmares009dednamespace.servicebus.windows.net/";
// az iot hub show --query properties.eventHubEndpoints.events.path --name {your IoT Hub name}
//private static final String eventHubsCompatiblePath = "{your Event Hubs compatible name}";
private static final String eventHubsCompatiblePath = "eventHubsCompatiblePathString";
// az iot hub policy show --name iothubowner --query primaryKey --hub-name {your IoT Hub name}
private static final String iotHubSasKey = "iotHubSasKeyString=";
private static final String iotHubSasKeyName = "iothubowner";
// Track all the PartitionReciever instances created.
private static ArrayList<PartitionReceiver> receivers = new ArrayList<PartitionReceiver>();
// Asynchronously create a PartitionReceiver for a partition and then start
// reading any messages sent from the simulated client.
private static void receiveMessages(EventHubClient ehClient, String partitionId)
throws EventHubException, ExecutionException, InterruptedException {
final ExecutorService executorService = Executors.newSingleThreadExecutor();
// Create the receiver using the default consumer group.
// For the purposes of this sample, read only messages sent since
// the time the receiver is created. Typically, you don't want to skip any messages.
ehClient.createReceiver(EventHubClient.DEFAULT_CONSUMER_GROUP_NAME, partitionId,
EventPosition.fromEnqueuedTime(Instant.now())).thenAcceptAsync(receiver -> {
System.out.println(String.format("Starting receive loop on partition: %s", partitionId));
System.out.println(String.format("Reading messages sent since: %s", Instant.now().toString()));
receivers.add(receiver);
while (true) {
try {
// Check for EventData - this methods times out if there is nothing to retrieve.
Iterable<EventData> receivedEvents = receiver.receiveSync(100);
// If there is data in the batch, process it.
if (receivedEvents != null) {
for (EventData receivedEvent : receivedEvents) {
System.out.println(String.format("Telemetry received:\n %s",
new String(receivedEvent.getBytes(), Charset.defaultCharset())));
System.out.println(String.format("Application properties (set by device):\n%s",receivedEvent.getProperties().toString()));
System.out.println(String.format("System properties (set by IoT Hub):\n%s\n",receivedEvent.getSystemProperties().toString()));
}
}
} catch (EventHubException e) {
System.out.println("Error reading EventData");
}
}
}, executorService);
}
public static void main(String[] args)
throws EventHubException, ExecutionException, InterruptedException, IOException, URISyntaxException {
final ConnectionStringBuilder connStr = new ConnectionStringBuilder()
.setEndpoint(new URI(eventHubsCompatibleEndpoint))
.setEventHubName(eventHubsCompatiblePath)
.setSasKeyName(iotHubSasKeyName)
.setSasKey(iotHubSasKey);
// Create an EventHubClient instance to connect to the
// IoT Hub Event Hubs-compatible endpoint.
final ExecutorService executorService = Executors.newSingleThreadExecutor();
final EventHubClient ehClient = EventHubClient.createSync(connStr.toString(), executorService);
// Use the EventHubRunTimeInformation to find out how many partitions
// there are on the hub.
final EventHubRuntimeInformation eventHubInfo = ehClient.getRuntimeInformation().get();
// Create a PartitionReciever for each partition on the hub.
for (String partitionId : eventHubInfo.getPartitionIds()) {
receiveMessages(ehClient, partitionId);
}
// Shut down cleanly.
System.out.println("Press ENTER to exit.");
System.in.read();
System.out.println("Shutting down...");
for (PartitionReceiver receiver : receivers) {
receiver.closeSync();
}
ehClient.closeSync();
executorService.shutdown();
System.exit(0);
}
}
Now I am trying to figure out how to recieve messages from publisher 1 only even when both publishers are running simultaneously. Thanks in Advance.
Azure IoT Hub is not a generic MQTT broker. It only supports the following topics:
devices/{device_id}/messages/devicebound/
devices/{device_id}/messages/devicebound/{property_bag}
And Event Hub can't specify device id too. Like what you have found.
There is a workaround but it is only working when your devices less and equal 10. This because the maximum custom endpoint you can create is 10.
That is you can use Service Bus Topic instead of Event Hub:
Device -> Azure IoT Hub -> Routing -> Endpoint "Service Bus Topic"
Add two service bus topic endpoints.
Add two routes for two endpoints:
Receive from the service bus topic:
subscriptionClient = new SubscriptionClient(ServiceBusConnectionString, TopicName, SubscriptionName);

groovy.lang.MissingPropertyException while Downloading Files from FTP Server

I want to create job in grails which download the files from ftp
server after certain interval of time say 2-3 days and store it on
specified local path. the same code with minor changes is written in
java which was working fine but when write the similar code in Grails
I'm facing the Error and not able to resolve it. Can any body Tell me
where I'm making mistake?
Following is the Error that I'm facing when job start.
JOB STARTED::************************************************************************************
2015-08-24 18:20:35,285 INFO org.quartz.core.JobRunShell:207 Job GRAILS_JOBS.com.hoteligence.connector.job.DownloadIpgGzipFilesJob threw a JobExecutionException:
org.quartz.JobExecutionException: groovy.lang.MissingPropertyException: No such property: ftpClient for class: com.hoteligence.connector.job.DownloadIpgGzipFilesJob [See nested exception: groovy.lang.MissingPropertyException: No such property: ftpClient for class: com.hoteligence.connector.job.DownloadIpgGzipFilesJob]
at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:111)
at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
Caused by: groovy.lang.MissingPropertyException: No such property: ftpClient for class: com.hoteligence.connector.job.DownloadIpgGzipFilesJob
at com.hoteligence.connector.job.DownloadIpgGzipFilesJob.execute(DownloadIpgGzipFilesJob.groovy:93)
at grails.plugins.quartz.GrailsJobFactory$GrailsJob.execute(GrailsJobFactory.java:104)
... 2 more
/* I've added all the related dependencies in grails Build Config.
*/
package com.hoteligence.connector.job
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import org.codehaus.groovy.grails.commons.ConfigurationHolder as ConfigHolder;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;
/**
* #author Gajanan
* this is back-end job which download Files from ftp server and store it on locally
*/
class DownloadIpgGzipFilesJob {
static triggers = {
simple repeatInterval: Long.parseLong(ConfigHolder.config.DEVICE_PING_ALERT_JOB_REPEAT_INTERVAL),
startDelay : 60000
}
def execute() {
try{
println "JOB STARTED::************************************************************************************";
/* following is the details which are required for server connectivity
*/
String server = ConfigHolder.config.IPG_SERVER_NAME;
int port = ConfigHolder.config.IPG_SERVER_PORT_NO;
String user = ConfigHolder.config.IPG_SERVER_USER_NAME;
String pass = ConfigHolder.config.IPG_SERVER_USER_PASSWORD;
String [] fileNames = ConfigHolder.config.IPG_DOWNLOADABLE_GZIP_FILE_LIST.split(",");
String downloadFilePath = ConfigHolder.config.IPG_GZIP_DOWNLOAD_LOCATION;
String fileDate = (todaysDate.getYear()+1900)+""+((todaysDate.getMonth()+1)<=9?("0"+(todaysDate.getMonth()+1)):(todaysDate.getMonth()+1))+""+todaysDate.getDate();
FTPClient ftpClient = new FTPClient();
/* Here we are making connection to the server and the reply
from server is printed on console
*/
ftpClient.connect(server, port);
showServerReply(ftpClient);
int replyCode = ftpClient.getReplyCode();
if (!FTPReply.isPositiveCompletion(replyCode)) {
System.out.println("Connect failed");
return;
}
boolean success = ftpClient.login(user, pass);
showServerReply(ftpClient);
if (!success) {
System.out.println("Could not login to the server");
return;
}
/* Here we are iterate the FileList and download them to specified directory
*/
for(int i =0; i<fileNames.length;i++) {
String fileName = "on_"+ConfigHolder.config.IPG_DATA_COUNTRY_CODE+fileNames[i]+fileDate+".xml.gz";
System.out.println(fileName);
downloadFtpFileByName(ftpClient,fileName,downloadFilePath+fileName);
}
}
catch (IOException ex) {
System.out.println("Oops! Something wrong happened");
ex.printStackTrace();
}
catch(Exception e) {
e.printStackTrace();
}
finally {
// logs out and disconnects from server
/* In finally block we forcefully close the connection and close the file node also
*/
try {
if (ftpClient.isConnected()) {
ftpClient.logout();
ftpClient.disconnect();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
/* this function is nothing but to print the ftp server reply after connection to ftp server
*/
private static void showServerReply(FTPClient ftpClient) {
String[] replies = ftpClient.getReplyStrings();
if (replies != null && replies.length > 0) {
for (String aReply : replies) {
System.out.println("SERVER: " + aReply);
}
}
}
/* This is the actual logic where we copy the file from ftp
and store on local directory
this method accept three parameter FtpClient object, Name of the file which has to be downloaded from server and the path where downloaded file has to be stored
*/
private static void downloadFtpFileByName(FTPClient ftpClient,String fileName,String downloadfileName){
System.out.println("Strat Time::"+System.currentTimeMillis());
try {
String remoteFile1 = "/"+fileName; // file on server
File downloadFile1 = new File(downloadfileName); // new file which is going to be copied on local directory
OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
Boolean success = ftpClient.retrieveFile(remoteFile1, outputStream1);
if (success) {
System.out.println("File"+fileName+" has been downloaded successfully.");
}
else
{
System.out.println("File"+fileName+" has been DOWNLOAD FAILURE....");
}
outputStream1.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("END Time::"+System.currentTimeMillis());
}
}
Move this line:
FTPClient ftpClient = new FTPClient();
Outside of the try { ... } catch() block (ie, move it up to before the try)
You are declaring the local variable inside the try, then trying to use it in the finally block

Spring integration + logging response time for http adapters(or any endpoint)

As part of non-functional requirements, I have to log the response time for each http-outbound calls in my spring integration flow.
I have a series of http:outbound-gateway's which make REST API calls (request/response in JSON). I have to log different things like request payload, service endpoint name, status (success/failure).
I have tried to use ChannelInterceptorAdapter like:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.channel.interceptor.ChannelInterceptorAdapter;
import org.springframework.stereotype.Component;
#Component(value = "integrationLoggingInterceptor")
public class IntegrationLoggingInterceptor extends ChannelInterceptorAdapter {
private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationLoggingInterceptor.class);
#Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
LOGGER.debug("Post Send - Channel " + channel.getClass());
LOGGER.debug("Post Send - Headers: " + message.getHeaders() + " Payload: " + message.getPayload() + " Message sent?: " + sent);
}
#Override
public Message<?> postReceive(Message<?> message, MessageChannel channel) {
try {
LOGGER.debug("Post Receive - Channel " + channel.getClass());
LOGGER.debug("Post Receive - Headers: " + message.getHeaders() + " Payload: " + message.getPayload());
} catch(Exception ex) {
LOGGER.error("Error in post receive : ", ex);
}
return message;
}
}
But I am not able to figure out how to get response times for each http:outbound-gateway.
Any pointers/suggestions/hints/advice would be highly appreciated.
Right, you should write Interceptor but not for channel and for <int-http:outbound-gateway>. There is a feature <request-handler-advice-chain>
It can be any implementation of AOP Advice. For your purpose the MethodInterceptor is a good choice. The advice is applied for AbstractReplyProducingMessageHandler.handleRequestMessage, where the real 'hard' work is done.

PostSaveDocument call agent asynchronously

I have an Xpage page with a single Notes document datasource.
After saving a document I want to (conditionally) trigger an agent. The agent takes some time to process and we don't want the user to have to wait for the result, so it should be executed asynchronously.
I've managed to get it working from client side JS by using an XHR to the agent URL, but I would like to do it server side so I can control the "Next page" better. When using .run() or .runonserver() the client waits till the agent completes.
Any idea how I could trigger an agent (from SSJS) on PostSaveDocument without the client waiting for the result?
Try to look at Thread and Jobs application on OpenNTF.org. There are nice demos of running task in background, check it here
As Martin suggested I used the JobScheduler example on OpenNtf and modified it to suit my needs. Resulting code can be found below. Any comments or improvements are welcome.
import java.security.AccessController;
import java.security.PrivilegedAction;
import lotus.domino.Agent;
import lotus.domino.Database;
import lotus.domino.NotesException;
import lotus.domino.Session;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import com.ibm.domino.xsp.module.nsf.ThreadSessionExecutor;
public class JobRunner {
public static void start(String dbPath, String agentName, String paramDocId) {
synchronized (JobRunner.class) {
runningJob = new ISPJob(dbPath, agentName, paramDocId);
runningJob.addJobChangeListener(new JobChangeAdapter() {
public void done(IJobChangeEvent event) {
System.out.println("Done event");
runningJob = null;
}
});
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
runningJob.schedule();
return null;
}
});
}
}
private static ISPJob runningJob;
private static final class ISPJob extends Job {
private ThreadSessionExecutor<IStatus> executor;
private String docId;
private String dbPath;
private String agentName;
public ISPJob(String paramDbPath, String paramAgentName, String paramDocId) {
super(paramDocId);
this.docId = paramDocId;
this.dbPath = paramDbPath;
this.agentName = paramAgentName;
this.executor = new ThreadSessionExecutor<IStatus>() {
#Override
protected IStatus run(Session session) throws NotesException {
System.out.println("Job started" + docId);
System.out.println(" >> Session created: "
+ session.getUserName() + ", Effective User:"
+ session.getEffectiveUserName());
Database db = session.getDatabase(null,dbPath);
if (db != null) {
try {
if (!db.isOpen()) db.open();
if (db.isOpen()) {
System.out.println(" >> Database opened: "
+ db.getTitle());
Agent agent = db.getAgent(agentName);
try {
System.out.println(" >> Agent Started: " + agent.getName());
agent.run(docId);
System.out.println(" >> Agent Ran: " + agent.getName());
} finally {
agent.recycle();
}
}
} finally {
db.recycle();
}
}
System.out.println("Job completed");
return Status.OK_STATUS;
}
};
}
protected IStatus run(IProgressMonitor monitor) {
try {
return executor.run();
} catch (Exception ex) {
return Status.CANCEL_STATUS;
}
}
};
}
You could use a session bean (so it won't get destroyed) that kicks off an Java thread. Or you could issue in code a server console command. Or you implement a DOTS listener.
This may/may not be an option depending on your application requirements but I am having good success calling function in the onClientLoad event which essentially kicks off the process after the XPage has fully loaded.

Resources