Why #PreDestory not working on websocket #ServerEndpoint? - java

I log some message to see the lifecycle of #ServerEndpoint. PostConstruct, onOpen, onClose are triggered in turns, but #PreDestroy is never triggered. Do I miss something?
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/")
public class ServerWebSocket {
#PostConstruct
public void initialize() {
System.out.println("PostConstruct");
}
#OnOpen
public void open(Session session) {
System.out.println("OnOpen");
}
#OnClose
public void close(Session session) {
System.out.println("OnClose");
}
#PreDestroy
public void destroy() {
System.out.println("PreDestroy");
}
}
I use GlassFish4 with bean.xml in WEB-INF
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
version="1.1" bean-discovery-mode="all">
</beans>

#OnOpen and #OnClose callbacks are triggered by the lifecycle of every WebSocket session.
There is no any CDI scope specified, which could be used with WebSocket endpoints. And this is ok, because it has it's own session.
So, why is #PostConstruct triggered? WebSocket specification says, that:
Websocket endpoints running in the Java EE platform must have full dependency injection support as described in the CDI specification.
And #PostConstruct API Doc points:
The PostConstruct annotation is used on a method that needs to be executed after dependency injection is done to perform any initialization. ... This annotation MUST be supported on all classes that support dependency injection.
Why #PreDestroy then doesn't work? I think, Websocket endpoints behave like singletons, and #PreDestroy will be triggered during removing of the instance, which will occur just before application stop. You could check it in your environment by stopping application from the GlassFish administration console.

Related

How can I intercept a request to check authorization before the view class instantiation occurs in a Vaadin 14 web app?

I'm trying to integrate Apache Shiro's Annotation-based Authorization (authz) into a Vaadin 14 web app. I've looked into some publicly available solutions regarding this topic:
ILAY - authorization for Vaadin;
Secure Router Navigation (from the Setting up Spring Security for Vaadin applications tutorial).
They all seem to use the same solution, setup a VaadinServiceInitListener to add a BeforeEnterEvent listener where all the authz logic must be implemented.
I thinks one problem arises with this kind of solution:
Since Vaadin views are built from the class constructor, the target view class as already been instantiated when reaching the BeforeEnterEvent authz validation, which means that the view is processed whether or not the requester has authorization to access it.
How can I intercept the requests before the View classes are instantiated so I can do a proper authz check using Shiro's annotations?
There is currently not any good way of intercepting navigation requests before the navigation target class is instantiated.
As a general workaround, you should ensure that you're not doing anything that can have security implications in the constructor of the class but instead using methods such onAttach since they will be called only after the BeforeEnterEvent has been dispatched and only if no listener prevented the navigation.
This problem was recently addressed in the core framework through issue #4595. It has not yet been decided in which version of Vaadin the changes will be introduced because of the way they can impact backwards compatibility in some cases.
Since Vaadin doesn't offer "any good way of intercepting navigation requests before the navigation target class is instantiated", I took the long and winding road and came up with a solution based on a custom Interceptor. This allowed me to short circuit the requests before the view class instantiation occurs, with the following visible results:
Pros:
Security - code doesn't get executed by users not authorized to do so;
Performance - since I perform the authz verification earlier, all the overhead of running unnecessary code is gone.
Cons:
The need to use an additional annotation. It would be great to have a solution to integrate seamlessly with the existing Shiro annotations, any improvements are welcomed.
The solution
Add a new #ShiroSecuredannotation to bind with the interceptor:
package misc.app.security;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
#Inherited
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
#Retention(RetentionPolicy.RUNTIME)
#InterceptorBinding
public #interface ShiroSecured { }
Add a ShiroSecuredInterceptor and bind it to the previously defined custom annotation. Make sure to have a method annotated with #AroundConstruct so the calls to the constructor of classes annotated with #ShiroSecured get intercepted:
package misc.app.security;
import javax.interceptor.AroundConstruct;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
/**
* An interceptor for declarative security checks using the annotations from the
* {#code org.apache.shiro.authz.annotation} package.
*
*/
#ShiroSecured #Interceptor
public class ShiroSecuredInterceptor extends AnnotationsAuthorizingConstructorInterceptor {
#AroundConstruct
public Object checkAuthorization(final InvocationContext ic) throws Exception {
assertAuthorized(new InvocationContextToConstructorInvocationConverter(ic));
return ic.proceed();
}
private static class InvocationContextToConstructorInvocationConverter implements ConstructorInvocation {
private final InvocationContext context;
public InvocationContextToConstructorInvocationConverter(InvocationContext ic) {
context = ic;
}
#Override
public Object proceed() throws Throwable {
return context.proceed();
}
#Override
public Class getClazz() {
return context.getConstructor().getDeclaringClass();
}
}
}
Register the interceptor in beans.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans bean-discovery-mode="all" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd">
<interceptors>
<class>misc.app.security.ShiroSecuredInterceptor</class>
</interceptors>
</beans>
That summarizes the main pieces of the solution. The following screenshot lists all the class files I implemented in order to make it work. Basically I had to duplicate part of Shiro's logic related to MethodInvocation to make it work for ConstructorInvocation. The two Error classes are implementation of Vaadin's Router Exception Handling for Shiro's AuthorizationException and UnauthenticatedException, thrown when the authz validation fails.

How to initialize some class, which is not a Servlet on glassfish4? [duplicate]

This question already has an answer here:
Using special auto start servlet to initialize on startup and share application data
(1 answer)
Closed 7 years ago.
I have web application in Java code, which uses servlets. My question is how to initialize some java class, which is not servlet. I understand that if the client connects - the servlet then prints the output. But only "if client connects".
Is it possible to run some threads before any connections are made?
EDIT:
Thanks to answers, right now I'm trying to do it this way:
the class:
package com.xsistema.filemanager.application;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
*
* #author Ernestas Gruodis
*/
public class ServerInit implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("Initialized");
}
#Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("Destroyed");
}
}
And the glassfish-web.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="">
<context-root>/file-manager</context-root>
<class-loader delegate="true"/>
<jsp-config>
<property name="keepgenerated" value="true">
<description>Keep a copy of the generated servlet class' java code.</description>
</property>
</jsp-config>
<listener>
<listener-class>
com.xsistema.filemanager.application.ServerInit
</listener-class>
</listener>
</glassfish-web-app>
And I getting this error while deploying the application:
Warning: Unsupported deployment descriptors element listener-class
value com.xsistema.filemanager.application.ServerInit.
What's wrong here?
EDIT2:
Can not delete this question, appeared to be duplicate (it has the answers already). But I found the solution:
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.servlet.ServletContextEvent;
#Startup
#Singleton
public class Config {
#PostConstruct
public void init() {
// Do stuff during webapp's startup.
}
#PreDestroy
public void destroy() {
// Do stuff during webapp's shutdown.
}
}
Very nice and easy, and working :)
The preferred way to do this is to install a ServletContextListener.
These get a chance to run code when the container starts up and shuts down.
If the code affects only a single servlet (or needs to initialize something private to that servlet object), you could also do the work in the init method of the servlet and make sure that the servlet is loaded even before a request is made (via the load-on-startup parameter).
You may run your code that initializes the other classes in the init() method of one of your servlets.

How to initialize a web application in Apache Tomcat?

I was using WebSphere Application Server, and it gives a platform initialization listener which is invoked when an app gets started. Now, I am using Apache Tomcat, but have not found such stuff, and what I'm trying to do is do some initialization work before the application begins to serve requests.
How should I do it by Apache Tomcat?
You create a Listener class what implement ServletContextListener like this:
package com.vy;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
#WebListener
public class StartStopListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("Servlet has been started.");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("Servlet has been stopped.");
}
}
Add configuration information to WEB-INF\web.xml like this:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<listener>
<listener-class>com.vy.StartStopListener</listener-class>
</listener>
</web-app>
When run Tomcat, You will see result at console screen:
Servlet has been started.
Reference: http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html
You can use ServletContextListener API. Please read this link. You can go and checkout this tutorial
You should write custom application start-up code in this method
#Override
public void contextInitialized(ServletContextEvent arg0) {
System.out.println("ServletContextListener started");
}
Note : There will not be any issues while moving to another servers, if needed in future.

ContainerRequestFilter JBoss AS 7.1.1 RestEasy 3.0.6.Final

I am trying to set up a request filter because I'd like to check some http header information before calling my logic. Unfortunately my filter never gets called in JBoss AS7.1.1. I already tried to update the RestEasy implementation (module) to 3.0.6 like described in the RestEasy documentation. It says you just have to replace the directories delivered by the new implementation zip-file and I did so.
The AS started without any errors but the behavior does not change in any way. Each request stays unintercepted. I extracted this code from a more complex example but even this simple thing does not work:
Filter.java
import java.io.IOException;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ContainerRequestFilter;
import javax.ws.rs.ext.Provider;
#Provider
#Secured
public class SecurityFilter implements ContainerRequestFilter {
public void filter(ContainerRequestContext crc) throws IOException {
throw new IllegalStateException("Not in my house");
}
}
ItemsResource.java
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
#Path("/Items")
public class ItemsResource {
#GET
#Produces("application/json")
#Secured
public String getJson() {
return "{\"id:\" \"1\"}";
}
}
ApplicationConfig.java
#javax.ws.rs.ApplicationPath("rest")
public class ApplicationConfig extends Application {
}
Secured.java
import javax.ws.rs.NameBinding;
#NameBinding
public #interface Secured {}
I does not change anything if I try to use the interceptor and the resource without the annotation. I would expect all the requests have to be intercepted but non will. I don't have any glue what to do. May anybody help we with some piece of advice? Let be add some addition thing. I tried the same thing with Wildfly (JBoss 8.0.0 Final). Interception by using #NameBinding and applying a custom annotation does not work also but if I don't use the annotation and just annotate the interceptor with #Provider all of my request get intercepted. Do I have to migrate to Wildfly or what?
We were in the same problem.
We used 3.0.8.Final version of RESTeasy with the POM dependencies.
Also update the modules of the JBOSS (EAp 6.1) with the content of the zip file resteasy-jaxrs-3.0.7.Final.
The only diferece is that in the filter we use:
#Provider #PreMatching
#Precedence("SECURITY")
public class SecurityInterceptor implements ContainerRequestFilter{
#Override
public void filter(ContainerRequestContext arg0) throws IOException {
...
}
}
In addition we also need to register manually the Providers in the web.xml with:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.neology.rest.SecurityInterceptor</param-value>
</context-param>
Other problem in that we get stuck was with the Spring integration.
First is to verify the order of the *Listeners
<!-- RESTeasy Listener 1st -->
<listener>
<listener-class>
org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap
</listener-class>
</listener>
<!-- Spring Listener 2nd -->
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
Please also check your security filter chain. If you have configured your rest servlet mapping something like /rest/* you need to make Spring to don't filter the REST service. We use this in the Spring xml configuration:
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping" />
<mvc:resources mapping="/rest/**" location="/rest/" />
Hope this helps!
You can use Resteasy PreProcessInterceptor:
import org.jboss.resteasy.annotations.interception.ServerInterceptor;
import org.jboss.resteasy.spi.interception.PreProcessInterceptor;
import javax.ws.rs.ext.Provider;
#Provider
#ServerInterceptor
public class SecurityInterceptor implements PreProcessInterceptor {
#Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method) throws Failure, WebApplicationException {
if (/* Check if a user is currently authenticated */) {
// no current authenticated user: throw exception
throw new NotAuthenticatedException();
}
return null; // = continue without interrupting
}
}
Your problem is already mentioned:
Match Filter with specific Method through NameBinding on RESTeasy
you need to remove the #PreMatching and to make sure your Secured annotation is retained during Runtime (Retention = RUNTIME).
Add a Provider file under your META-INF/services , like : /META-INF/services/javax.ws.rs.ext.Providers , javax.ws.rs.ext.Providers is a file , the content is your path of filter like : com.hujiang.foe.instalment.liquidation.biz.impl.account.filter.ContextCleanFilter

Executing task after deployment of Java EE application

I have a Java EE application which should start a synchronization process with an external system once after its deployment.
How could I implement this requirement?
Below are listed a couple of popular methods for getting lifecycle callbacks in JavaEE apps.
Create a javax.servlet.ServletContextListener implementation
If you have a web component to your .ear file (embedded .war) or your deployment is a .war by itself you can add a ServletContextListener to your web.xml and get a callback when the server starts or is shutting down.
Example:
package com.stackoverflow.question
import javax.servlet.ServletContextListener;
import javax.servlet.ServletContextEvent;
public class MyServletContextListener implements ServletContextListener{
#Override
public void contextInitialized(ServletContextEvent contextEvent) {
/* Do Startup stuff. */
}
#Override
public void contextDestroyed(ServletContextEvent contextEvent) {
/* Do Shutdown stuff. */
}
}
and then add this configuration to your web.xml deployment descriptor.
$WAR_ROOT/WEB-INF/web.xml.
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee">
<listener>
<listener-class>com.stackoverflow.question.MyServletContextListener</listener-class>
</listener>
</web-app>
Create an EJB 3.1 #Startup Bean
This method uses an EJB 3.1 singleton to get a startup and shutdown callback from the server.
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.ejb.Startup;
import javax.ejb.Singleton;
#Singleton
#Startup
public class LifecycleBean {
#PostConstruct
public void init() {
/* Startup stuff here. */
}
#PreDestroy
public void destroy() {
/* Shutdown stuff here */
}
}
I tested the suggested solution which uses the #Startup and #PostConstruct annotations. It turned out that Glassfish does not complete the deployment of an application until all methods annotated with #PostConstruct have finished. So in my case the deployment would take from several minutes up to an hour.
But I figured out a different way to achive what I want. The best solution seems to be a timer callback method which cancels its timer after its execution.
#Stateless
public class SynchronisationService {
#Schedule(hour = "*", minute = "*", persistent = false)
protected void init(Timer timer)
{
doTheSync();
timer.cancel();
}
}
Using a non-persistent timer allows the timer to be re-created if the application server is restarted.
You can use the #Startup and #PostConstruct annotations to perform tasks on application startup.
Using a ServletContextListener, or a servlet that is initialized at startup, for example. Of course, this becomes much harder if you have multiple deployments of the application in a cluster, and only want this process to be run once.

Categories

Resources