Using GWT RPC from a GWTTestCase using Guice - gwt

I've configured my GWT app with Guice as documented here. With this setup the app works fine.
However what I'd like to do now is get a GWTTestCase to call a service using GWT RPC. To this end I've done this,
Updated my <app>JUnit.gwt.rpc so that the service URL maps to GuiceRemoteServiceServlet
Added an init() method to GuiceRemoteServiceServlet to initialise the Injector as per this comment
Unfortunately I'm still getting an error,
com.google.inject.ProvisionException: Guice provision errors:
Caused by: com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
at com.google.inject.servlet.GuiceFilter.getContext(GuiceFilter.java:132)
at com.google.inject.servlet.GuiceFilter.getRequest(GuiceFilter.java:118)
at com.google.inject.servlet.InternalServletModule$1.get(InternalServletModule.java:35)
.....
The object it's trying to provision is ServletContext. The cause of the error is due to the fact the GuiceFilter hasn't been called so the ServletContext hasn't been bound to ThreadLocal.
Is there any way of getting past this?

In the Junit environment you aren't getting two things that you normally get from the servlet container: the setup/destroy help from the GuiceServletContextListener and the filtering of the GuiceFilter, so you need to do these bits yourself.
You basically need to create another servlet that wraps your servlet and does all the setup/filtering that you'd normally see done by the servlet container; what I recommend is something like this:
Suppose your servlet is called AdriansGuicedGwtServiceServlet. Then create this in your testing directory:
public class TestAdriansGuicedGwtServiceServlet extends AdriansGuicedGwtServiceServlet {
private GuiceFilter filter;
#Override
public void init() {
super.init();
// move your injector-creating code here if you want to
// (I think it's cleaner if you do move it here, instead of leaving
// it in your main servlet)
filter = new GuiceFilter();
filter.init(new FilterConfig() {
public String getFilterName() {
return "GuiceFilter";
}
public ServletContext getServletContext() {
return TestAdriansGuicedGwtServiceServlet.this.getServletContext();
}
public String getInitParameter(String s) {
return null;
}
public Enumeration getInitParameterNames() {
return new Vector(0).elements();
}
});
}
#Override
public void destroy() {
super.destroy();
filter.destroy();
}
private void superService(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
super.service(req, res);
}
#Override
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException {
filter.doFilter(new FilterChain() {
public void doFilter (ServletRequest request, ServletResponse response)
throws IOException, ServletException {
superService(request, response);
}
});
}
}
And then in your <app>Junit.gwt.rpc have it map in TestAdriansGuicedGwtServiceServlet instead of your real servlet.

Related

How to send email from a servlet using threads or executor service?

Where executor service should be declared so it is available to other servlets and not new thread gets created for every new request
Can I do something like this and whenever need to send email, forward request to this servlet
Can you please suggest better design to use ExecutorService in servlet or any other way to send email from servlet?
public class EmailTestServlet extends HttpServlet
{
ExecutorService emailThreadPool = null;
public void init()
{
super.init();
emailThreadPool = Executors.newFixedThreadPool(3);
}
protected void doGet(HttpServletRequest request,HttpServletResponse response)
{
sendEmail(); //it will call emailThreadPool.execute();
}
public void destroy()
{
super.destroy();
}
}
Depends on whether CDI is available at your environment. It is available out the box in normal Jakarta EE servers, but in case of barebones servletcontainers such as Tomcat or Jetty you'd need to manually install and configure it. It's relatively trivial though and gives a lot of benefit: How to install and use CDI on Tomcat?
Then you can simply create an application scoped bean for the job like below:
#ApplicationScoped
public class EmailService {
private ExecutorService executor;
#PostConstruct
public void init() {
executor = Executors.newFixedThreadPool(3);
}
public void send(Email email) {
executor.submit(new EmailTask(email));
}
#PreDestroy
public void destroy() {
executor.shutdown();
}
}
In order to utilize it, simply inject it in whatever servlet or bean where you need it:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
#Inject
private EmailService emailService;
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
In case you find yourself in the unfortunate situation that you cannot use CDI, then you'll have to remove the #ApplicationScoped annotation from the EmailService class and reinvent the wheel by simulating whatever CDI is doing under the covers by manually fiddling with ServletContext#get/setAttribute() to simulate an application scoped bean. It might look like this:
#WebListener
public class ApplicationScopedBeanManager implements ServletContextListener {
#Override
public void contextCreated(ServletContextEvent event) {
EmailService emailService = new EmailService();
emailService.init();
event.getServletContext().setAttribute(EMAIL_SERVICE, emailService);
}
#Override
public void contextDestroyed(ServletContextEvent event) {
EmailService emailService = (EmailService) event.getServletContext().getAttribute(EMAIL_SERVICE);
emailService.destroy();
}
}
In order to utilize it, rewrite the servlet as follows:
#WebServlet("/any")
public class AnyServlet extends HttpServlet {
private EmailService emailService;
#Override
public void init() {
emailService = (EmailService) getServletContext().getAttribute(EMAIL_SERVICE);
}
#Override
protected void doPost(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException {
Email email = new Email();
// ...
emailService.send(email);
}
}
See also:
What is recommended way for spawning threads from a servlet in Tomcat
How to run a background task in a servlet based web application?
Background process in Servlet

EJB not initializing in Wildfly 9.0.0 using #EJB

I'm trying to migrate from EJB2.x to EJB3.x and i'm using Wildfly 9.0.0.
The old EJB2.x is working in JBoss 4.2.2 and this is how it looks like:
public interface WUFFacadeRemote extends EJBObject {
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
public interface WUFFacadeHome extends EJBHome {
public WUFFacadeRemote create();
}
public class WUFFacade {
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
}
public class WUFAction extends HttpServlet implements IAction {
public void doPost(HttpServletRequest request, HttpServletResponse response) {
...
Object objRef = ic.lookup("java:comp/env/wUF");
com.wuf.WUFFacadeHome home = (com.wuf.WUFFacadeHome) PortableRemoteObject.narrow(objRef, com.wuf.WUFFacadeHome.class);
engine = home.create();
//engine gets the reference, and I can use it normally.
...
}
}
I also have the ejb-jar.xml and it's working. Now, the solution I was thinking to EJB3.x and Wildfly 9.0.0 is as below:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet implements IAction {
#EJB
private WUFFacadeRemote engine;
public void doPost(HttpServletRequest request, HttpServletResponse response) {
//Here I should be able to use my engine.
//Wildfly starts and I call the page, engine is not null at this moment,
//but after I call the page again, it becomes null and remains null.
}
}
#Stateless
#Remote(WUFFacadeRemote.class)
public class WUFFacade extends RootFacade implements WUFFacadeRemote, Serializable {
public WUFFacade() { }
#EJB
FUFHome home;
public ClientData getItems(ClientData data) {
//code here
}
public ClientData save(ClientData data) {
//code here
}
private Col load(ClientData data,InitialContext ic) {
//here i'm calling home.
// but home is always null. It was supposed to have the #EJB reference initialized.
//But instead I get a null pointer...
home.findByFilter(loader);
}
}
#Remote(FUFHome.class)
public interface FUFHome {
FUF create(FUFValue fUFValue);
FUF findByPrimaryKey(FUFPK pk);
Collection findByFilter(FacadeLoader loader);
}
public interface WUFFacadeRemote{
public ClientData getItems(ClientData data);
public ClientData save(ClientData data);
}
I don't have ejb-jar.xml anymore, the deploy is sucessfully done and Wildfly starts with no errors. Then the first time I call the page in question, it seems that #EJB is working (Debug is "Proxy for remote EJB StatelessEJBLocator for "bus-facade/WUFFacade", view is interface com.wuf.WUFFacadeRemote, affinity is None"), the value is not null, but for all subsequent calls, my variable is null and I got a NullPointerException.
I really don't know what i'm doing wrong (maybe i'm completely lost), but to me, #EJB should be working correctly like that. What am I missing? Thanks.
As i'm using EJB3.x i'm just using annotations now, (this seems to be ok).
JNDIs:
JNDI bindings for session bean named FUF in deployment
java:global/fumo/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:app/bus-entities-fumo/FUF!apyon.components.fumo.fuf.FUF
java:module/FUF!apyon.components.fumo.fuf.FUF
java:global/fumo/bus-entities-fumo/FUF
java:app/bus-entities-fumo/FUF
java:module/FUF
JNDI bindings for session bean named WUFFacade
java:global/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:app/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:module/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:jboss/exported/fumo/bus-facade-fumo/WUFFacade!apyon.fumo.wuf.WUFFacadeRemote
java:global/fumo/bus-facade-fumo/WUFFacade
java:app/bus-facade-fumo/WUFFacade
java:module/WUFFacade
I think I found a possible solution to the problem. I'll still try to find another one, but this is good so far.
After changing to a .war and keeping my other projects in .ears it's working. Maybe the problem was because I have a RootController servlet im my main.ear, which is the starting point of the aplication. The context starts there and then it redirects to fumo.ear (now fumo.war).
For some reason, I always was getting a null in my EJB after entering a page. It was always hapening when I first entered a JSP and tried to call the page again. My solution to this is:
#WebServlet(urlPatterns = "windows/wUF.do", loadOnStartup = 1)
public class WUFAction extends HttpServlet {
private WUFFacadeRemote engine;
public void doGet(HttpServletRequest req, HttpServletResponse resp) {
doPost(req, resp);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) {
if(engine == null) {
InitialContext ic;
try {
ic = new InitialContext();
engine = (WUFFacadeRemote) ic.lookup("java:global/fumo/WUFFacade!fumo.wuf.WUFFacadeRemote");
} catch (NamingException e) {
e.printStackTrace();
}
}
//here I always have the context now.
}
}
And as a .war my structure now looks like this:
So other annotations like #Inject and #EJB are now working. Always when i'm being redirect from a JSP calling a Servlet or some action, I first check if the context is not null, otherwise I lookup it. My #Stateless are working and the #PersistenceContext and #Remote are working too.
#Stateless
public class WUFFacade implements WUFFacadeRemote {
#Inject
private FUFRules rules;
#EJB
private FUFHome home;
private Col load(ClientData data, InitialContext ic) throws InterfaceException {
try {
// home here is nor null anymore.
Collection res = (Collection) home.findByFilter(loader);
...
} catch (InterfaceException e) {
e.printStackTrace();
}
...
return data;
}
}
So I'd like to thank everyone who helped in the thread. It was a good way to understand and see the problem or to find a workaround. As I said, I'll still try the .ear in the future, but as a simplified packaging it definitely works.

Spring boot how to get resource method in request filter

I am building a REST API with Spring Boot, and now trying to create a custom filter class where I need to access the resource method that would be invoked by the request. I need that in order to check if the method is annotated with a certain annotation, e.g.
#Component
#ApplicationScope
public class MyFilter extends OncePerRequestFilter {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
Method method = // get the target method somehow
if (method.isAnnotationPresent(MyAnnotation.class)) {
// business logic here
}
filterChain.doFilter(request, response);
}
}
With RESTEasy I would do something like this
#Context
private ResourceInfo resourceInfo;
where ResourceInfo has methods to get the resource class and method that is the target of the request. Is there a similar class in Spring Boot that would do the same job?

Java EE Servlet and REST path clashing

I am trying to write a Java web application that provides both HTML and REST interface. I would like to create a servlet that would provide the HTML interface using JSP, but data should also be accessible via REST.
What I already have is something like this for the REST:
#javax.ws.rs.Path("/api/")
public class RestAPI {
... // Some methods
}
and
#WebServlet("/servlet")
public class MyServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Howdy at ");
}
}
Now, when I change the #WebServlet("/servlet") annotation to #WebServlet("/"), the servlet stops working probably due to path clash with the REST.
How can I provide REST on specific path and HTML in the root?
Thank you,
Lukas Jendele
This seems to work OK for me. What I did:
In my pom.xml, I have a dependency on org.wildfly.swarm:undertow (for Servlet API) and org.wildfly.swarm:jaxrs (for JAX-RS). And of course the Swarm Maven plugin.
For servlet, I have just this one class:
#WebServlet("/")
public class HelloServlet extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello from servlet");
}
}
For JAX-RS, I have these 2 classes:
#ApplicationPath("/api")
public class RestApplication extends Application {
}
#Path("/")
public class HelloResource {
#GET
public Response get() {
return Response.ok().entity("Hello from API").build();
}
}
To test, I run curl http://localhost:8080/ and curl http://localhost:8080/api. Results are as expected. (Maybe my example is too simple?)

Spring REST Security with Custom Filters and Multiple Authentication Providers - Target Method Not Called On Successful Authentication

I'm implementing a Spring security module for REST services. It involves 2 custom filters and 2 custom authentication providers. The application is using Spring 4.1.5.RELEASE with Spring security 4.0.0.RELEASE. No XML.
After successful authentication my custom AuthenticationSuccessHandler is invoked alright. Inside the onAuthenticationSuccess method, I simply reconstruct the original URL and forward the request. But the request never gets to the REST service. I don't get any errors, just an empty response with status 200. I checked by removing the custom filters and the service is called alright. I just cannot figure out even after calling the success handler. why the request never makes it to the target? Please help.
WebSecurityConfigurerAdapter implementation:
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(usernamePasswordAuthProvider)
.authenticationProvider(tokenAuthProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(serviceRegistrationValidatingFilter,
CustomUsernamePasswordAuthenticationFilter.class)
.addFilter(authFilter);
}
AuthenticationEntryPoint implementation:
#Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
#Override
public void commence(HttpServletRequest request,
HttpServletResponse response, AuthenticationException authException)
throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
authException.getMessage());
}
}
AuthenticationSuccessHandler implementation:
#Component
public class RestAuthenticationSuccessHandler extends
SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String path = Joiner.on("/")
.join(request.getServletPath(), request.getPathInfo())
.replaceAll("//", "/");
request.getRequestDispatcher(path).forward(request, response);
clearAuthenticationAttributes(request);
}
}
Log showing the filter chain that gets created (package names and hash codes omitted for brevity). My filters are where I want them to be.
INFO: Creating filter chain: AnyRequestMatcher, [WebAsyncManagerIntegrationFilter, SecurityContextPersistenceFilter, HeaderWriterFilter, CsrfFilter, LogoutFilter, ServiceRegistrationValidatingFilter, CustomUsernamePasswordAuthenticationFilter, RequestCacheAwareFilter, SecurityContextHolderAwareRequestFilter, AnonymousAuthenticationFilter, SessionManagementFilter, ExceptionTranslationFilter, FilterSecurityInterceptor]
So the issue turned out to be using Spring MockMvc. I needed to use forwardedUrl("forwardToUrl") for verification. The actual forward wasn't happening, as I posted above. Also content().string("expectedString") didn't work, content was coming as blank.
It appears that MockMvc is designed to test behavior, not data.
mockMvc.perform(get("/form"))
.andExpect(status().isOk())
.andExpect(content().string("expectedString"))
.andExpect(forwardedUrl("forwardToUrl"));