How to add offline event handling in Openfire plugin? - java

I am java newbie . I need to handle offline sessions in Openfire plugin. From plugin development doc I am able to understand the basics , but I am not getting how can I handle offline event of openfire.
There is a class "SessionEventDispatcher" in package org.jivesoftware.openfire.event
There we have following predefined events:
session_created
session_destroyed
anonymous_session_created
anonymous_session_destroyed
resource_bound
These events then have listener , which is implemented in the Presence plugin.
Please help me understand how to proceed if I need to add offline event as well.
I am saving online users in redis but some how user sessions in openfire is less than users in redis, which means I am not handling some offline event in my plugin due to which user session is created and get added in redis , but user session is not closed explicitly which is handled to get remove from redis, and I face this discrepancy.

please correct me if I don`t understand your question clearly.
Do you examine interface org.jivesoftware.openfire.user.PresenceEventListener?
For example I implement that interface :
public class CustomPresenceEventListener implements PresenceEventListener {
private static final Logger LOG = LoggerFactory.getLogger(CustomPresenceEventListener.class);
#Override
public void availableSession(ClientSession session, Presence presence) {
LOG.info("\n\n=======SESSION AVAILABLE=========\n");
try {
LOG.info("USER : {}", session.getUsername());
} catch (UserNotFoundException e) {
LOG.info(e.getMessage(), e);
}
LOG.info("\n================\n\n");
}
#Override
public void unavailableSession(ClientSession session, Presence presence) {
LOG.info("\n\n=======SESSION UNAVAILABLE=========\n");
try {
LOG.info("USER : {}", session.getUsername());
} catch (UserNotFoundException e) {
LOG.info(e.getMessage(), e);
}
LOG.info("\n================\n\n");
}
#Override
public void presenceChanged(ClientSession session, Presence presence) {
}
#Override
public void subscribedToPresence(JID subscriberJID, JID authorizerJID) {
}
#Override
public void unsubscribedToPresence(JID unsubscriberJID, JID recipientJID) {
}
And add/remove this listener with :
PresenceEventDispatcher.addListener(presenceEventListener);
PresenceEventDispatcher.removeListener(presenceEventListener);
And when I connect to Openfire I will see in the file info.log something like that :
=======SESSION AVAILABLE=========
2017.03.29 14:27:01 .CustomPresenceEventListener - USER : 25
2017.03.29 14:27:01 .CustomPresenceEventListener -
And when I leave Openfire logs will be :
=======SESSION UNAVAILABLE=========
2017.03.29 14:27:34 .CustomPresenceEventListener - USER : 25
2017.03.29 14:27:34 .CustomPresenceEventListener -
So you could add any action you want when user enter/leave Openfire.

Related

How to implement Async behaviour in response to send email while response return in Java

I am using spring application and we have a SOA architecture based on REST API. I have an API for example create user(http://myapp/api/createUser)
So now when a user is created we need to send an email to user right away.I did implement it but it wait for email method to send email and return success/failure, which consumes time.
Please how can i return success response from API right away by starting the e-mail part in thread and run in background and send mail to user. or if failure then logged in database.
Please suggest me the API or framework for that I dont want to implement Messaging Queue like Rabbit MQ or Active Queue.
Please share those implementation that do not create problem in live production server by spawning threads.
Use #Async in your email sending method.
Ref: http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/scheduling/annotation/Async.html
Example:
#Async
public void sendNotificaitoin(User user) throws MailException {
javaMailSender.send(mail);
}
To enable #Async to work, use #EnableAsync in your configuration.
#SpringBootApplication
#EnableAsync
public class SendingEmailAsyncApplication {
public static void main(String[] args) {
SpringApplication.run(SendingEmailAsyncApplication.class, args);
}
}
Use it like below:
#RequestMapping("/signup-success")
public String signupSuccess(){
// create user
User user = new User();
user.setFirstName("Dan");
user.setLastName("Vega");
user.setEmailAddress("dan#clecares.org");
// send a notification
try {
notificationService.sendNotificaitoin(user);
}catch( Exception e ){
// catch error
logger.info("Error Sending Email: " + e.getMessage());
}
return "Thank you for registering with us.";
}

Recovering from HBase server failure using Async HBase client

I'm currently trying to find a way to deal with unexpected HBase failures in my application. More specifically, what I'm trying to solve is a case where my application inserts data to HBase and then HBase fails and restarts.
In order to check how my application reacts to that scenario I wrote an application that uses HBase Async client by doing a tight loop and saving the results in HBase. When I start the application I can see rows are saved into the table, if during this time I intentionally fail my HBase server and restart it the client seems to reconnect but new insertions are not saved into the table
The code looks like this:
HConnection connection = HConnectionManager.createConnection();
HBaseClient hbaseClient = new HBaseClient(connection);
IntStream.range(0, 10000)
.forEach(new IntConsumer() {
#Override
public void accept(int value) {
try {
System.out.println("in value: " + value);
Thread.sleep(2000);
Get get = new Get(Bytes.toBytes("key"));
hbaseClient.get(TableName.valueOf("testTable"), get, new ResponseHandler<Result>() {
#Override
public void onSuccess(Result response) {
System.out.println("SUCCESS");
}
#Override
public void onFailure(IOException e) {
System.out.println("FAILURE");
}
});
urlsClient.save("valuekey", "w" + value, new FailureHandler<IOException>() {
#Override
public void onFailure(IOException failure) {
System.out.println("FAILURE");
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
This is obviously just a simple test but what I'm trying to achieve is that the async client will successfully save new rows after I restarted my HBase server. What the asynchronous HBase clients prints to me if I actually print the stacktrace in the "onFailure" method is:
org.apache.hadoop.hbase.ipc.RpcClient$CallTimeoutException: Call id=303, waitTime=60096, rpcTimeout=60000
at org.apache.hadoop.hbase.ipc.AsyncRpcChannel.cleanupCalls(AsyncRpcChannel.java:612)
at org.apache.hadoop.hbase.ipc.AsyncRpcChannel$1.run(AsyncRpcChannel.java:119)
at io.netty.util.HashedWheelTimer$HashedWheelTimeout.expire(HashedWheelTimer.java:581)
at io.netty.util.HashedWheelTimer$HashedWheelBucket.expireTimeouts(HashedWheelTimer.java:655)
at io.netty.util.HashedWheelTimer$Worker.run(HashedWheelTimer.java:367)
at java.lang.Thread.run(Thread.java:745)
And so my questions are:
How should one deal with a situation like I mentioned using the specified async client?
If this async client is no longer relevant could someone suggest a different async client that can perform asynchronous puts? I tried the BufferedMutator but it does not seem to actually flush any contents but just fails with the following java.lang.IllegalAccessError: tried to access method com.google.common.base.Stopwatch.<init>()V from class org.apache.hadoop.hbase.zookeeper.MetaTableLocator (but this gets a little off topic so I wont expand anymore)
Thanks
It's been quite a long time since I asked this question but I ended up using the HBase high availability instead of finding a way to solve it with code

PageExpiredException, migration to wicket 1.5 not working

I am trying to server a particular error page when session timeouts to my users.
For this i configured the error page on my Application's init method.
But this thing is not working.
I set up the session tiemout in 1 minute, after that nothing happen, I went through the logs, but wicket didn't throw any PageExpiredException.
When session timeouts wicket simply logs it as:
Session unbound: C061F4F21C41EDF13C66795DAC9EDD02
Removing data for pages in session with id 'C061F4F21C41EDF13C66795DAC9EDD02'
this is my init method in my customApplication
protected void init() {
super.init();
this.getApplicationSettings().setPageExpiredErrorPage(SessionExpiredPage.class);
...
...
}
my SessionExpiredPage.class
public class SessionExpiredPage extends TecnoAccionPage {
public SessionExpiredPage() {
this.setOutputMarkupId(true);
this.add(new Label("title", "SesiĆ³n Expirada"));
CSSLoader.get().appendCssUntil(this, SessionExpiredPage.class);
}
}
And i have a custom implementation of AbstractRequestCycleListener i override the OnException method But, when my session expire, I never pass in the "onException".
Thank You, best regards.
For some reason there is no PageExpiredException thrown by wicket, while it can reconstruct requested page, even if the session was expired.
So, there is another way to deal with this problem.
You have to override onRequestHandlerResolved method in your AbstractRequestCycleListener, to catch all incoming requests, and check there if incoming session id is outdated.
To check this, you must have list of the expired sessions in your app and catch unbound event to manage them.
This is going to be something like that:
public class YourApp extends WebApplication {
//synchronized list with ids
private List<String> unboundSessions = new CopyOnWriteArrayList<String>();
#Override
protected void init() {
super.init();
this.getApplicationSettings().setPageExpiredErrorPage(SessionExpiredPage.class);
//add request listener
getRequestCycleListeners().add(new AbstractRequestCycleListener() {
public void onRequestHandlerResolved(RequestCycle cycle, IRequestHandler handler) {
if (handler instanceof IPageRequestHandler) {
HttpServletRequest request = (HttpServletRequest) cycle.getRequest().getContainerRequest();
String sessionId = request.getRequestedSessionId();
//check whether the requested session has expired
boolean expired = sessionId != null && !request.isRequestedSessionIdValid();
//if session is not valid and it was really expired
if (expired && unboundSessions.contains(sessionId)) {
//then remove it from unbound list
unboundSessions.remove(sessionId);
//and throw exception
throw new PageExpiredException("Expired");
}
}
super.onRequestHandlerResolved(cycle, handler);
}
});
...
}
//this method called when any session is invalidated, so check your manual invalidating calls (if you ever do them)
#Override
public void sessionUnbound(String sessionId) {
super.sessionUnbound(sessionId);
if (!unboundSessions.contains(sessionId)) {
unboundSessions.add(sessionId);
}
}
}
Unbound sessions list needs for us to know, that user's session is really expired, since the expired variable in our listener could be also true when user just openes our site after redeploy, for example. His session is taken from his cookies and it could be already expired, but that would be weird to redirect him to SessionExpiredPage immediately.
It looks like a workaround, but it should work.

How to get an existing websocket instance

I'm working on an application that uses Websockets (Java EE 7) to send messages to all the connected clients asynchronously. The server (Websocket endpoint) should send these messages whenever a new article (an engagement modal in my app) is created.
Everytime a connection is established to the websocket endpoint, I'm adding the corresponding session to a list, which I could be able to access outside.
But the problem I had is, when I'm accessing this created websocket endpoint to which all the clients connected from outside (any other business class), I've get the existing instance (like a singleton).
So, can you please suggest me a way I can get an existing instance of the websocket endpoint, as I can't create it as new MyWebsocketEndPoint() coz it'll be created by the websocket internal mechanism whenever the request from a client is received.
For a ref:
private static WebSocketEndPoint INSTANCE = null;
public static WebSocketEndPoint getInstance() {
if(INSTANCE == null) {
// Instead of creating a new instance, I need an existing one
INSTANCE = new WebSocketEndPoint ();
}
return INSTANCE;
}
Thanks in advance.
The container creates a separate instance of the endpoint for every client connection, so you can't do what you're trying to do. But I think what you're trying to do is send a message to all the active client connections when an event occurs, which is fairly straightforward.
The javax.websocket.Session class has the getBasicRemote method to retrieve a RemoteEndpoint.Basic instance that represents the endpoint associated with that session.
You can retrieve all the open sessions by calling Session.getOpenSessions(), then iterate through them. The loop will send each client connection a message. Here's a simple example:
#ServerEndpoint("/myendpoint")
public class MyEndpoint {
#OnMessage
public void onMessage(Session session, String message) {
try {
for (Session s : session.getOpenSessions()) {
if (s.isOpen()) {
s.getBasicRemote().sendText(message);
}
} catch (IOException ex) { ... }
}
}
But in your case, you probably want to use CDI events to trigger the update to all the clients. In that case, you'd create a CDI event that a method in your Websocket endpoint class observes:
#ServerEndpoint("/myendpoint")
public class MyEndpoint {
// EJB that fires an event when a new article appears
#EJB
ArticleBean articleBean;
// a collection containing all the sessions
private static final Set<Session> sessions =
Collections.synchronizedSet(new HashSet<Session>());
#OnOpen
public void onOpen(final Session session) {
// add the new session to the set
sessions.add(session);
...
}
#OnClose
public void onClose(final Session session) {
// remove the session from the set
sessions.remove(session);
}
public void broadcastArticle(#Observes #NewArticleEvent ArticleEvent articleEvent) {
synchronized(sessions) {
for (Session s : sessions) {
if (s.isOpen()) {
try {
// send the article summary to all the connected clients
s.getBasicRemote().sendText("New article up:" + articleEvent.getArticle().getSummary());
} catch (IOException ex) { ... }
}
}
}
}
}
The EJB in the above example would do something like:
...
#Inject
Event<ArticleEvent> newArticleEvent;
public void publishArticle(Article article) {
...
newArticleEvent.fire(new ArticleEvent(article));
...
}
See the Java EE 7 Tutorial chapters on WebSockets and CDI Events.
Edit: Modified the #Observer method to use an event as a parameter.
Edit 2: wrapped the loop in broadcastArticle in synchronized, per #gcvt.
Edit 3: Updated links to Java EE 7 Tutorial. Nice job, Oracle. Sheesh.
Actually, WebSocket API provides a way how you can control endpoint instantiation. See https://tyrus.java.net/apidocs/1.2.1/javax/websocket/server/ServerEndpointConfig.Configurator.html
simple sample (taken from Tyrus - WebSocket RI test):
public static class MyServerConfigurator extends ServerEndpointConfig.Configurator {
public static final MyEndpointAnnotated testEndpoint1 = new MyEndpointAnnotated();
public static final MyEndpointProgrammatic testEndpoint2 = new MyEndpointProgrammatic();
#Override
public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException {
if (endpointClass.equals(MyEndpointAnnotated.class)) {
return (T) testEndpoint1;
} else if (endpointClass.equals(MyEndpointProgrammatic.class)) {
return (T) testEndpoint2;
}
throw new InstantiationException();
}
}
You need to register this to an endpoint:
#ServerEndpoint(value = "/echoAnnotated", configurator = MyServerConfigurator.class)
public static class MyEndpointAnnotated {
#OnMessage
public String onMessage(String message) {
assertEquals(MyServerConfigurator.testEndpoint1, this);
return message;
}
}
or you can use it with programmatic endpoints as well:
public static class MyApplication implements ServerApplicationConfig {
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> endpointClasses) {
return new HashSet<ServerEndpointConfig>
(Arrays.asList(ServerEndpointConfig.Builder
.create(MyEndpointProgrammatic.class, "/echoProgrammatic")
.configurator(new MyServerConfigurator())
.build()));
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
return new HashSet<Class<?>>(Arrays.asList(MyEndpointAnnotated.class));
}
Of course it is up to you if you will have one configurator used for all endpoints (ugly ifs as in presented snippet) or if you'll create separate configurator for each endpoint.
Please do not copy presented code as it is - this is only part of Tyrus tests and it does violate some of the basic OOM paradigms.
See https://github.com/tyrus-project/tyrus/blob/1.2.1/tests/e2e/src/test/java/org/glassfish/tyrus/test/e2e/GetEndpointInstanceTest.java for complete test.

BlazeDS StreamingAMF: How to detect when flex client closes the connection?

I have a Flex application that connects to a BlazeDS server using the StreamingAMF channel.
On the server-side the logic is handled by a custom adapter that extends ActionScriptAdapter and implements FlexSessionListener and FlexClientListener interfaces.
I am asking how can I detect which "flex-client" has closed a connection when for example the user is closing the browser? (so I can clean some infos inside the database)
I tried using the following:
1. To manually manage the command messages:
#Override
public Object manage(final CommandMessage commandMessage) {
switch (commandMessage.getOperation()) {
case CommandMessage.SUBSCRIBE_OPERATION:
System.out.println("SUBSCRIBE_OPERATION = " + commandMessage.getHeaders());
break;
case CommandMessage.UNSUBSCRIBE_OPERATION:
System.out.println("UNSUBSCRIBE_OPERATION = " + commandMessage.getHeaders());
break;
}
return super.manage(commandMessage);
}
But the clientID's are always different from the ones that came.
2. Listening for sessionDestroyed and clientDestroyed events
#Override
public void clientCreated(final FlexClient client) {
client.addClientDestroyedListener(this);
System.out.println("clientCreated = " + client.getId());
}
#Override
public void clientDestroyed(final FlexClient client) {
System.out.println("clientDestroyed = " + client.getId());
}
#Override
public void sessionCreated(final FlexSession session) {
System.out.println("sessionCreated = " + session.getId());
session.addSessionDestroyedListener(this);
}
#Override
public void sessionDestroyed(final FlexSession session) {
System.out.println("sessionDestroyed = " + session.getId());
}
But those sessionDestroyed and clientDestroyed methods are never called. :(
I made it the following way, by using a custom adapter and a static class with a list of connected clients.
#Override
public Object manage(final CommandMessage commandMessage) {
switch (commandMessage.getOperation()) {
case CommandMessage.SUBSCRIBE_OPERATION:
// add user info
// be aware - each time the selector changes this method is called. So when you add user info check to see if you are not duplicating the clients.
addInfoAboutUser(commandMessage.getHeader("DSId").toString(), commandMessage.getClientId().toString());
break;
case CommandMessage.UNSUBSCRIBE_OPERATION:
clearUserInfo(commandMessage.getClientId().toString());
break;
}
return null;
}
-
Code INFO:
addInfoAboutUser() and clearUserinfo() are private methods in my class that manage the static list of connected clients.
-
NOTE: when a selector is changed from the flex client side the manage() method will be called twice: 1st to unsubscribe and 2nd to subscribe with the new selector.
You need to catch the event onbeforeunload and call a method on server which will cleanup all the client related data. Otherwise there is no way for the Flex client to automatically detect that it is unloaded.
The session should be destroyed when the maximum inactivity interval is exceeded...if the web.xml is properly configured.
Had the same problem as you ... solved it by a "hack" of BlazeDS ... I documented it on my confluence. Perhaps it helps with your problem:
http://dev.c-ware.de/confluence/display/PUBLIC/Litening+for+BlazeDS+client+logins+and+logouts

Categories

Resources