JEE: How to intercept a #PostCostruct method? - interceptor

I have a bean having:
void initialize() method annotated with #PostConstruct.
void release() method annotated with #PreDestroy.
Some other methods.
In addition that bean has a #Interceptors annotation defining some interceptors.
One of those interceptors has methods annotated with
#AroundConstruct
#AroundInvoke
#AroundTimeout
#PostConstruct
#PreDestroy
In each of those methods I put some logging, so I can see which and when the interceptor methods are called. And the call order looks like this:
Interceptor's #AroundConstruct method is entered.
InvocationContext: Target is null, method is null, constructor is set.
Beans constructor is called.
The call exists through Interceptor's #AroundConstruct method.
InvocationContext: Target is the bean instance, method is null, constructor is set.
Interceptor's #PostConstruct method is called, calls proceed() and returns.
InvocationContext: Target is the bean instance, method is null, constructor is set.
After the previous call returned completely the bean's #PostConstruct method is called.
I was very surprised realizing that the #PostConstruct is not called during the bean's #PostConstruct method call, but between the construction of the bean and calling the bean's #PostConstruct method. Also the call of the bean's #PostConstruct method is not intercepted at all, not by the interceptor's #PostConstruct method nor bi its #AroundInvoke method.
Is there any mistake on my side / my programs side?
Is there any way to intercept the bean's #PostConstruct method (same goes for the #PreDestroy method)?
I need to prepare the context(s) and fill them with some content. In addition it would be also nice for other method deep down the call stack later to know that the call was triggered by the container through one of those two methods.

As I couldn't find any answer on that in the Internet, I went through some debugging and found out the following (used WildFly 15.0.1.Final):
When a bean is instantiated:
Entering interceptor's #AroundConstruct (InvocationContext: Constructor set)
Executing bean's constructor
Leaving interceptor's #AroundConstruct (InvocationContext: Constructur and target set)
Entering interceptor's #PostConstruct (InvocationContext: Constructur and target set)
Executing bean's #PostConstruct
Leaving interceptor's #PostConstruct (InvocationContext: Constructur and target set)
This means that you don't know which method is called, you only know that the #PostConstruct method of the bean is called. I guess that's because the #PostConstruct method of the bean is executed as some kind of interceptor, but that is only an assumption on my side.
When you execute a bean's method:
Entering interceptor's #AroundInvoke (InvocationContext: Method and target set)
Executing bean's method
Leaving interceptor's #AroundInvoke (InvocationContext: Method and target set)
When a bean is destroyed:
Entering interceptor's #PreDestroy (InvocationContext: Target set)
Executing bean's #PreDestroy
Leaving interceptor's #PreDestroy (InvocationContext: Target set)
I hope that this will be also helpful to others.

Related

Apache Camel Stateful Bean

Based on below example , how to make my Add bean as Stateful:
from("direct:firstRoute")
.bean(Add.class)
.bean(Add.class,"setIntA(1)")
.bean(Add.class,"setIntB(1)")
.log("${body}")
.setHeader(SpringWebserviceConstants.SPRING_WS_SOAP_ACTION,simple("http://tempuri.org/Add"))
.to("spring-ws:http://www.dneonline.com/calculator.asmx")
.convertBodyTo(AddResponse.class)
.log("${body}");
That mean first i need to create the bean then Calling the setIntA method then setIntB without loosing the value in each step .

Where do I put the Authentication Filter for Spring Boot 1.3.3

So I know what the problem is, I just don't know how to fix it.
Problem
I am using Spring Boot 1.3.3 and the CorsFilter is set like the following
public class WebConfig extends WebMvcConfigurerAdapter {
#Autowired
private Environment env;
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://192.168.1.132:8100")
.allowedHeaders("Accept", "Content-Type","X-Auth-Token", "Origin", "Pragma","Cache-Control",
"If-Modified-Since","Authorization")
.exposedHeaders("X-Auth-Token")
.allowedMethods("PUT","POST","GET","OPTIONS")
.allowCredentials(true).maxAge(3600);
}
}
Secuity Config
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/save-user","/test","/error","/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
http.addFilterAfter(new CustomStatelessAuthenticationFilter(tokenAuthenticationService),
UsernamePasswordAuthenticationFilter.class);
...
}
The problem I am having is that I am using a Custom Token something like X-Auth-Token to validate the user. BUT CustomStatelessAuthenticationFilter is being called before the CorsRegistry. Before Chrome makes a call it does a OPTIONS call to make sure the application is legit. It won't allow me to pass the X-AUTH-TOKEN header without validating the call is legit. So it does not allow me to pass the X-AUTH-TOKEN until the server gets a response status OK From the server. Well since the CustomStatelessAuthenticationFilter gets call first, the X-AUTH-TOKEN returns as null. To fix this I had to do something like this...
CustomStatelessAuthenticationFilter
#Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
boolean debug = this.logger.isDebugEnabled();
if(debug) {
this.logger.debug("Custom.Custom Stateless Authentication");
}
if (request.getMethod().equals("OPTIONS")) {
response.addHeader("Access-Control-Allow-Origin", "http://192.168.1.132:8100");
response.addHeader("Access-Control-Allow-Headers", "X-Auth-Token");
response.addHeader("Access-Control-Expose-Headers", "X-Auth-Token");
response.setStatus(HttpServletResponse.SC_OK);
} else {
SecurityContextHolder.getContext().setAuthentication(
this.tokenAuthenticationService.getAuthentication((HttpServletRequest) request));
filterChain.doFilter(request, response);
}
}
In other words I have to return to the client that Status is OK manually before it will make the real request. It makes two request, one to make sure the OPTION call returns a OK (Pre Flight Request), then it makes another that actually makes the call with the X-Auth-Token in it. I don't want to do this because its completely ignoring my CorsMapping. I want it to check the CorsMapping First before continuing on. So where do I setup the authenitcation correctly so it already accepts the OPTIONS check first before actually authenticating.
I've also tried something like the following in my security config
http.addFilterAfter(new CustomStatelessAuthenticationFilter(tokenAuthenticationService),
CsrfFilter.class);
I advise a Upvote for this because I have not found a solid solution. So far the addCorsMappings has cause me more of a pain than the older solution of just adding a CorsFilter in older versions

How to resolve "You have not started an Objectify context" in JUnit?

I've got some Objectify test code running in JUnit and I'm getting this error:
java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
at com.googlecode.objectify.impl.ref.LiveRef.<init>(LiveRef.java:31)
at com.googlecode.objectify.Ref.create(Ref.java:26)
at com.googlecode.objectify.Ref.create(Ref.java:32)
at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImpl.create(DownloadTaskRepositoryImpl.java:35)
at com.netbase.followerdownloader.repository.DownloadTaskRepositoryImplTest.setUp(DownloadTaskRepositoryImplTest.java:45)
How do I resolve this for test code?
Jeff Schnitzer answered this here: https://groups.google.com/forum/#!topic/objectify-appengine/8HinahG7irg. That link points to https://groups.google.com/forum/#!topic/objectify-appengine/O4FHC_i7EGk where Jeff suggests the following quick and dirty workaround:
My #BeforeMethod starts an objectify context (ObjectifyService.begin())
My #AfterMethod closes the objectify context
Jeff suggests we use ObjectifyService.run() instead but admits it's more work.
Here's how my implementation looks:
public class DownloadTaskRepositoryImplTest {
// maximum eventual consistency (see https://cloud.google.com/appengine/docs/java/tools/localunittesting)
private final LocalServiceTestHelper helper =
new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig()
.setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
private Closeable closeable;
#Before
public void setUp() {
helper.setUp();
ObjectifyRegistrar.registerDataModel();
closeable = ObjectifyService.begin();
}
#After
public void tearDown() {
closeable.close();
helper.tearDown();
}
I also had this issue and noticed that I had not added the ObjectifyFilter to my web.xml
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I also had to include Objectify and guava jars in my WEB-INF>lib directory and include them in my build path.
I was facing the same error and this solusion worked for me
I have an app based on Endpoints that uses Objectify. When I leave it with the default/automatic scaling, everything works great. Once I enable basic scaling, though, I get the following exception when executing the endpoint method:
[INFO] java.lang.IllegalStateException: You have not started an Objectify context. You are probably missing the ObjectifyFilter. If you are not running in the context of an http request, see the ObjectifyService.run() method.
[INFO] at com.googlecode.objectify.ObjectifyService.ofy(ObjectifyService.java:44)
[INFO] at com.myco.myapp.dao.datastore.OfyService.ofy(OfyService.java:62)
The good news is that this goes away when you enable RequestDispatcher
support in the web.xml file like so. I think this is a documentation
issue, then, but I didn't know if everyone would agree if I edited the
Wiki page directly. Here is the proposed web.xml entry, which worked
for me:
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Improving michael-osofsky answer, I add this to my ofy helper class
public static void registerDataModel() {
try {
factory().register(Profile.class);
} catch (Exception e){
e.printStackTrace();
}
}
and remplace
ObjectifyRegistrar.registerDataModel();
for this
OfyService.registerDataModel();
OfyService.java
public static void registerDataModel() {
try {
factory().register(Profile.class);
} catch (Exception e){
e.printStackTrace();
}
}
As Jeff Schnitzer says in the link provided by Michael Osofsky:
In your tests you should have some notion of a 'request' even if it is just conceptual. If "each test is a request by itself", then you can use #Before/#After in conjunction with ObjectifyService.begin() to demarcate the requests. However, this is probably not actually how your tests work - it isn't how my tests work.
He then goes on to say:
This would be prettier with JDK8 closures but the idea is straightforward - you're wrapping some unit of work in a context which represents a request. It would probably be smart to add even more context like authentication in that wrapper too.
I came up with the following implementation of his idea. With the solution below, you can ensure each call to a servlet handler gets a fresh Objectify session while still making your servlet handler calls in a single line of code. It also decouples your tests from explicitly worrying about Objectify, and allows you to add additional non-Objectify context around your servlet handlers.
My solution below works with Objectify 5.1.22. I tried using Objectify 6+, but I had problems that seem to be related to this.
First, define a custom Supplier that is able to capture the exceptions thrown by a servlet handler.
#FunctionalInterface
public interface ServletSupplier<T> {
T get()
throws ServletException, IOException;
}
Next, define a wrapper method that accepts your new custom Supplier as an input, and wrap the call to ServletSupplier.get() in a try-with-resources block that calls ObjectifyService.begin(). You must also register your entity classes before calling ServletSupplier.get().
public <T> T runInServletContext(ServletSupplier<T> servletMethod)
throws ServletException, IOException {
try (Closeable session = ObjectifyService.begin()) {
ObjectifyService.register(MyObj.class);
return servletMethod.get();
}
}
Finally, anywhere in your tests that you call the servlet handler you should do so using the wrapper method.
MyObj myObjPost = runInServletContext(() -> getServlet().doPost(request, response));
// Assert results of doPost call.
MyObj myObjGet = runInServletContext(() -> getServlet().doGet(request, response));
// Assert results of doGet call.
Just in case someone ends up here (as I originally did) looking up the same problem but for the ktor "main.kt" server instead of unit tests...
After looking at the ObjectifyFilter source code, I added
val closer = ObjectifyService.begin()
... real service here ...
closer.close()
around my actual servlet code and that fixed the problem.

onCompletion in Camel 2.14

I'd like to wrap the result of a processed message into some reply-object to answer a webservice. This is my test-route:
this.from("cxf:someEndpoint")
.process(new SomeProcessorThatMightThrowAnException())
.process(new SomeOtherProcessorThatMightThrowAnException())
.log("normal end of route");
Nevermind if there was an exception or not, the result should be wrapped in some object, that is given back to the caller of my ws.
In camel 2.13.x I did this by adding an other processor to the end of the route and to do the same in 'onException'.
Now I tried to simplify this (technical thing and handle it outside of the 'functional route') in camel 2.14 (2.14 because of 'modeBeforeConsumer'), and added this to my routebuilder:
onCompletion()
.modeBeforeConsumer()
.process(new ConvertToWsReplyProcessor());
This ConvertToWsReplyProcessor should handle an Exception, but I found no way to see, if there was an Exception, because exchange.getProperty(Exchange.EXCEPTION_CAUGHT, Throwable.class) is allways null.
Questions:
1) Is there a way to find out if there was an excetion in onCompletion()?
2) The only way I found to prevent camel from dumping a stacktrace is to use onException(Ex...).handled(true), are there others?
3) How are these onXY processed? Do they get a copy of the exchange? And is onCompletion called last?
OnCompletionProcessor just remove some exchange properties before processing the exchange, that could explain why you cannot fine the exception here.
As camel use onException to handle the exception, I'm afraid you have to do it that way.

Camel exchange inout is not maintaining the exception in exchange

I created a camel route without INOUT exchange pattern and the route looks like
direct:start > bean:myBean?method=handle
I'm sending payload using ProducerTemplate's send method
Exchange response = producerTemplate.send(endpointUri, exchange);
I set the exception on exchange in the bean's handle method, but its not retained in the response.
Is there something I'm missing.
You should throw an exception from the bean if you want to signal an exception.
I found where camel's hiding the exception. Since I marked the exchange as handled and marked for rollback, camel is setting the exception to null and moved it to properties.
I was able to retrieve it using
result.getProperty(Exchange.EXCEPTION_CAUGHT)

Resources