I have a webservice deployed on a weblogic server. Whenever any client instance hits that webservice, I have to store the clients details and send mail to the client every 24 hours until the client takes the required action.
So in order to send mail every 24 hours, I've written a timer code, that should call the method to send mail every 24 hours.
My question is : Since the code is on server, And there can be 100s of clients that will hit my webservice and start their own timer instance. So does having these multiple timer instance(say 100 or more) affect the server performance?
If yes, please suggest an alternative code I can use to trigger mails sending every 24 hours after the webservice is hit.
Update - My Code
public static final Map<String, Timer> userDeactivationPendingMap = new HashMap();
#GET
#Path("/check-deactivation-status/{username}")
#Produces(MediaType.APPLICATION_JSON)
public String checkDeactivationStatus(#PathParam("username") final String username) {
String returnJsonString = "Email has been sent to IProc team to take further actions on it.";
Timer timer = new Timer();
TimerTask dailyTask = new TimerTask() {
#Override
public void run() {
hitEmailSendingApi(username, "abc#test.com");
}
};
// schedule the task to run starting now and then every day...
timer.schedule(dailyTask, 0l, 1000 * 60 * 60 * 24);
userDeactivationPendingMap.put(username, timer);
return returnJsonString;
}
#Path("/initializeUserDeactivationRequest") #GET
#Produces(MediaType.TEXT_HTML)
public String deactivateUser(#QueryParam("username") String username) {
//code to deactivate user
//Cancelling timer
Timer timer = userDeactivationPendingMap.get(username);
timer.cancel();
return "<h4>User Deactivated Successfully!!<h4>";
}
private void hitEmailSendingApi(String username, String iprocTeamMailAddress) {
String domain = RequestFilter.getRequest().getRequestURL().toString();
String contextPath = RequestFilter.getRequest().getContextPath();
String serverURL = domain.substring(0, domain.indexOf(contextPath));
String servletPath = RequestFilter.getRequest().getServletPath();
serverURL = serverURL + contextPath + servletPath;
EmailSender.sendEmail(iprocTeamMailAddress, "Action Required: Clear User's Pending Requisitions for Account Deactivation", "Hi Team"
+ ",\n\n A new request for user deactivation has been raised by " + username + ".\n\n"
+ "Once all the requisitions are cleared, please press on below link for deactivating the user.\n"
+ serverURL + "/deactivate-account/initializeUserDeactivationRequest?username=" + (username));
}
Related
I'm integrating with a payments processor and am trying to deal with the scenario where:
user clicks pay and a request is made to our server
our server makes a request to the payment processor
there is a significant delay on the payment processor side
after a certain threshold e.g. 60 seconds, we alert the user that their payment was unsuccessful
after 70 seconds the payment processor returns a successful response.
So I need to start an API call to the payment processor from within the HTTP call from the UI, then if it takes more than 60 seconds, end the HTTP call and return an error to the user, then if the API call to the payment processor eventually succeeds (say after 70 seconds), send an email to the admin team.
I'm thinking of something like this:
import javax.ws.rs.client.*;
import java.util.Timer;
import java.util.TimerTask;
...
boolean overThreshold = false;
int timeout = 60; // seconds
TimerTask task = new TimerTask() {
#Override
public void run() {
overThreshold = true;
// return a message to user here saying their payment could not be processed
}
};
new Timer(true).schedule(task, timeout * 1000);
Client client = ClientBuilder.newClient();
WebTarget webTarget
= client.target({url of payment processor});
Invocation.Builder builder = webTarget.request()
.header(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON);
final Response response = builder.post(Entity.json(new Gson().toJson(request)));
if (overThreshold) {
// send alert email here
}
There are a few problems, e.g. the run() method has void return value, error with overThreshold as being accessed from a inner class. Is there a more elegant way of doing this?
Using Future.get(timeout) from an ExecutorService should handle this quite cleanly.
For example:
ExecutorService executor = Executors.newCachedThreadPool();
// ... set up builder as before ...
Future<Response> responseFuture = executor.submit(
() -> builder.post(Entity.json(new Gson().toJson(request))));
try {
Response response = responseFuture.get(timeout, TimeUnit.SECONDS);
// return normal response here
} catch (TimeoutException ex) {
executor.submit( () -> {
Response lateResponse = responseFuture.get();
// send overThreshold alert email here
// Dummy return - prefer Callable to Runnable here for exception handling
return null;
} );
// return a message to user here saying their payment could not be processed
}
The choice of ExecutorService could be tuned to fit, or equally be a shared thread pool elsewhere in the application.
I have been building my GWT app, using JSONP to communicate with a push server (my own code, based on Netty library). The communication function of the GWT app looks like the following, which sends queries stored in in queryList and processes received data from server via function processDataFromServer. You may notice that right after a fail or a success of communicating, the function calls itself again for keeping connection with server:
ArrayList<String>queryList;
boolean querying = false;
public void queryJsonpServer() {
if (querying) {
return;
}
querying = true;
String jsonString = queryList.isEmpty() ? “” : queryList.remove(0);
String url = postUrl + (!jsonString.isEmpty() ? “?jsonp=" + URL.encodeQueryString(jsonString) : "");
JsonpRequestBuilder jsonp = new JsonpRequestBuilder();
jsonp.setTimeout(60 * 1000);
jsonp.requestObject(url, new AsyncCallback<MyJsonpObject>() {
#Override
public void onFailure(Throwable caught) {
querying = false;
queryJsonpServer();
}
#Override
public void onSuccess(MyJsonpObject o) {
processDataFromServer(o);
querying = false;
queryJsonpServer();
}
});
}
The code works fine if the communication are successes (onSuccess called).
However, once it fails (onFailure called, because of timeout for example), even the function (queryJsonpServer) is called again (I am sure a new query is sent, server receives that query and sends back new data), the function is stuck to receive that new data (onSuccess has not been called since that fail). After a while onFailure called again because of timeout. The problem repeats: query via onFailure, receive nothing, onFailure called again...
Anyone has idea about that problem? Thanks
I'm trying to add a "delayed disconnect" mechanism to a WebSocket chat I'm developing. What this means is that if the user is disconnected, but reconnects within a certain time limit - I'm going to use 30 seconds as an example - the disconnection is ignored. The reason for this is a proof-of-concept for if the user briefly loses their connection - e.g. a mobile user entering a lift.
I've decided to use cookies for this. The logic I've figured out is that when a WebSocket is opened, it also opens a HttpSession. From that, I can check to see if a cookie with a particular id exists. If it does, then they are not treated as a new user. However, for this I need to be able to set the expiry time of the cookie for 30 seconds after the socket has been closed.
I already know that Cookie.setMaxAge() would do that, but when I tried this inside the OnClose() method on the server, the server threw a NullPointerException. That's not really a surprise, since I was obviously trying to access the user session after it had been closed.
So, is there a way to do this?
Update 16th of Feb I've decided to try resetting the cookie entirely when a message is sent. This partly works, since the cookies are generated and added to the HttpSession, but upon reconnecting the server thinks the user is entirely new. So, I think my problem is that the cookie isn't being sent to the user.
Update 2 After reading this question, I've moved the cookie generation into a configuration class that is called on a successful handshake. If the request does not have a cookie, it is treated as an entirely new connection, and logs that to the System console as proof of concept. One thing I've had to do was to extend the lifetime of the cookie at the start: currently, it's 10 minutes as a ballpark figure. If I can't find out how to do exactly what I said up above, I'll go with this.
Update 19th of February I've ditched cookies altogether. See my solution.
I solved this by ditching cookies altogether. I've just shown the methods in the relevant classes; if this isn't enough, I will edit my answer to include the full code.
Inside the configuration class, I get the x-forwarded-for header of the request. This matches the IP address of the client, especially since my backend server is behind a proxy. If the user's IP address is in a list of users, their connection is "refreshed"; otherwise, they are added to the list. Upon disconnection, for whatever reason, the user is marked as disconnected.
A separate ConnectionMonitor class implements the Runnable interface and runs every 10 seconds, and checks to see if any clients have been disconnected for more than 30 seconds. If they have been, then they are removed from the list of users.
MyConfigClass.modifyHandshake()
#Override
public void modifyHandshake(ServerEndpointConfig config,
HandshakeRequest request,
HandshakeResponse response)
{
HttpSession theSession = (HttpSession) request.getHttpSession();
config.getUserProperties().put(HttpSession.class.getName(), theSession);
String ID = request.getHeaders().get("x-forwarded-for").get(0);
if (ChatroomServerEndpoint.users.containsKey(ID))
{
// if this user isn't new, add them back onto the list
User oldUser = ChatroomServerEndpoint.users.get(ID);
System.out.println("An old user with " + ID + " has returned.");
ChatroomServerEndpoint.users.remove(oldUser);
ChatroomServerEndpoint.users.put(ID, oldUser);
oldUser.toggleConnection(true);
System.out.println(oldUser + ", " + ChatroomServerEndpoint.users.size() );
}
else
{
// add a new user to the list
System.out.println("A new user with ID " + ID + " has arrived!");
User newUser = new User(ID);
ChatroomServerEndpoint.users.put(ID, newUser);
System.out.println(newUser + ", " + ChatroomServerEndpoint.users.size() );
}
// put this ID into the configuration for proof of concept
config.getUserProperties().put("newUser", ID);
}
ConnectionMonitor.updateUsers() runs in a separate thread.
void updateUsers()
{
for(String id : ChatroomServerEndpoint.users.keySet())
{
User theUser = ChatroomServerEndpoint.users.get(id);
if (theUser.getStatus() == User.Connection.DISCONNECTED)
{
// get the time at which the user disconnected
Calendar disconnectDate = theUser.getdisconnectionDate();
// Calendar.getTime.getTime returns milliseconds,
// so, multiply maxDisconnectTime by 1000 to see if the user has expired
if (theDate.getTime().getTime() - disconnectDate.getTime().getTime()
>= maxDisconnectTime * 1000 )
{
System.out.println(id + " has timed out");
ChatroomServerEndpoint.users.remove(id);
}
}
}
}
User
public class User {
// the ID is the user's IP address
private String id;
// connection status
public enum Connection
{
CONNECTED,
DISCONNECTED
}
private Connection status;
// the time of disconnection
private Calendar disconnectionDate;
// each user needs a WebSocket Session to be able to send and receive messages
private Session userSession;
/**
* #return the id of this user
*/
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
/**
* #return connection status
*/
public Connection getStatus() {
return status;
}
public void setStatus(Connection status) {
this.status = status;
}
public Calendar getdisconnectionDate() {
return disconnectionDate;
}
public void setdisconnectionDate(Calendar disconnectionDate) {
this.disconnectionDate = disconnectionDate;
}
/**
* #return the userSession
*/
public Session getUserSession() {
return userSession;
}
/**
* #param userSession the userSession to set
*/
public void setUserSession(Session userSession) {
this.userSession = userSession;
}
/**
* #param newID the new ID of the user
*/
public User (String newID)
{
this.id = newID;
this.status = Connection.CONNECTED;
}
/**
* Toggles the connection
* #param toggle - if true, the user is connected
*/
public void toggleConnection(boolean toggle)
{
if (toggle == false)
{
status = Connection.DISCONNECTED;
disconnectionDate = Calendar.getInstance();
}
else
{
status = Connection.CONNECTED;
disconnectionDate = Calendar.getInstance();
disconnectionDate.add(Calendar.HOUR, 1); // give an extra hour to prevent them being disconnected too soon
}
}
}
Good morning, I have the following code:
int numero = 22492;
String PhnNoStr = String.valueOf (numero);
String transaction = WriteText(tipoTransacao);
String SmsStr = "ECART" + "" + transaction + idToken;
System.out.println ("Message:" + smsStr);
MessageConnection msgCon = null;
msgCon = (MessageConnection) Connector.open ("sms :/ /" + + phnNoStr ": 500");
TextMessage TxtMsg = (TextMessage) msgCon.newMessage (MessageConnection.TEXT_MESSAGE);
txtMsg.setPayloadText (smsStr);
msgCon.send (TxtMsg);
so I send that message by default it returns me a message. I can send and receive this message, however I need to intercept when I receive this message, does anyone know how I can do this?
Thank you
You can use PushRegistry to have your midlet launched when a SMS is received and midlet is not running.
PushRegistry.registerConnection("sms://:500", "your_package.Your_MIDlet", "*");
To handle incoming SMS, you need to open connection and listen for incoming message, eg:
class SMSHandler implements MessageListener, Runnable {
public void start() {
...
connection = (MessageConnection) Connector.open("sms://:500", Connector.READ);
connection.setMessageListener(this);
}
public void notifyIncomingMessage(MessageConnection messageConnection) {
(new Thread(this)).start();
}
public void run() {
final Message message = connection.receive();
...
}
(The reason for processing the message in another thread is that blocking I/O should not be done in system callback - at least WTK emulator will print warning, and on some phones midlet will just freeze).
I'm currently using Topic based communication using JADE. I'm able to register a JADE agent using jade.core.messaging.TopicManagementFEService thereby connecting to the main-container in the same platform.
The details are below:
Main-Container: a simple LAMP/WAMP Server that hosts the Main-Container.
Client: An Android Emulator(testing purpose) to connect to the main-container.
Currently,
Server starts the main-container
Android emulator connects to the Main-container successfully (Agent created along with Topic Mgmt Service enabled)
Server is sending messages based on a specific topic.
But my Android Client is not able to receive this message although the topic registered is the same on both ends!
You can see the code below:
Server Side:
TopicManagementHelper topicHelper = (TopicManagementHelper) getHelper(TopicManagementHelper.SERVICE_NAME);
final AID sensorTopic = topicHelper.createTopic("JADE");
topicHelper.register(sensorTopic);
addBehaviour(new TickerBehaviour(this, TIMER_VALUE_IN_MILLISECONDS) {
private static final long serialVersionUID = -2567778187494378326L;
public void onTick() {
ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
msg.addReceiver(eventTopic);
msg.setContent(eventValue);
myAgent.send(msg);
}
});
Android Side:
// Registering on Android Side as well
TopicManagementHelper topicHelper = (TopicManagementHelper) getHelper(TopicManagementHelper.SERVICE_NAME);
topic = topicHelper.createTopic("JADE"); // See, same topic!
topicHelper.register(topic);
behaviour = new myBehaviour(this, TIMER_VALUE_IN_MILLISECONDS, topic);
addBehaviour(behaviour);
private class myBehaviour extends TickerBehaviour {
private static final long serialVersionUID = 4782913834042415090L;
AID topic;
Agent agent;
MessageTemplate tpl;
public myBehaviour(Agent a, long period, AID topic) {
super(a, period);
this.agent = a;
this.topic = topic;
}
public void onTick() {
tpl = MessageTemplate.MatchTopic(topic);
ACLMessage msg = receive(tpl);
if (msg != null) {
logger.log(Level.INFO, "Agent "+ agent.getLocalName() +
": Message about topic "+ topic.getLocalName() +" received. \n" +
"Content is " + msg.getContent());
data = msg.getContent();
} else {
logger.log(Level.INFO, "In here..."); // Always executes only this code!
block();
}
}
}
Where am I going wrong here? It always executes the else part in the Android side which is obvious to say that message received is NULL!
Never mind. The logic was wrong. The Android-Agent was not identifying itself to the Central-Agent.
I set the Ontology so that the Central Agent is able to identify such message and sends the message accordingly. Now, it is receiving messages!
Self-help works sometimes! ;-)
Receiving topic messages doesn't work correctly with Android up to version 4.3.0 in JADE. Android can send out topic messages but can't receive them. I found this out through my own issues. I've posted more info about it in my own question on stack overflow.
Take a look. JADE Leap Android App unable to receive topic messages