I'm kind of new in web development with Java.
I am developing a web service and I've chosen REST / Jersey for it.
I want to init some stuff on startup of the service and to keep them
all along the life of the service.
First question : Is the constructor of the Jersey Servlet a good place to do that ?
Basically, what I want to do is to load a config.ini file located in my WEB-INF directory.
Following this help, I understand I need a ServletContext to load my file as a resource.
However, it is not clear to me how to get this ServletContext in a Jersey Servlet, as it is not really an instance of a servlet, but rather a POJO with some annotations.
I wanted to try this tip, but the attribute "context" is null in the constructor. I think that Jersey might populate it after the constructor. Right ?
So how is the right way to do this ?
Here is my code so far :
/** Main REST servlet */
#Path("/")
public class Servlet {
// ----------------------------------------------------
// Constants
// ----------------------------------------------------
static private final String CONFIG_PATH = "/WEB-INF/config.ini";
// ----------------------------------------------------
// Attributes
// ----------------------------------------------------
/** Context */
#Context ServletContext context;
// ----------------------------------------------------
// Constructor
// ----------------------------------------------------
/** Init the servlet */
public Servlet() {
// Load config.ini from WEB-INF
Config.config = new Config(
this.context.getResourceAsStream(CONFIG_PATH));
// FAIL! this.context is null ...
}
// ----------------------------------------------------
// URI Handlers
// ----------------------------------------------------
/** Welcome page */
#GET
#Path("/")
#Produces(MediaType.TEXT_HTML)
public String welcome() {
return "<h1>Hi there.</h1>";
}
}
Any help would be much appreciated.
Thanks in advance,
Raphael
Using a ContextListener isn't the JAX-RS way to do this-- the ContextListener is the "next layer down," as it were, in the servlet API.
You can put the annotated declaration in the constructor parameters and it will be passed to the constructor:
public Servlet(#Context ServletContext context) {
Using the #Context annotation for a data member initializes that member after the object is constructed, as you discovered.
Another way to do this is to move the initialization of the Config object into some sort of init call, and only initialize it when it's needed, i.e. lazy initialization. Then the ServletContext data member will already have been set by the Jersey framework.
Good Luck!
Kirk
I am not familiar with Jersey, but generally in a Java web application, I think the right thing to do would be to create a ContextListener.
A context listener is a class that implements the interface javax.servlet.ServletContextListener and is configured in your web.xml. It has a method that is executed when the application is first loded into your container, and another one that is executed when the application is stopped, so it is the ideal place to put some one-time initialization stuff, and clean-up things before the application is stopped.
So the steps are :
create your Listener class, implement the contextInitialized(ServletContextEvent sce) method. In this method you receive a ServeltContextEvent that has getServletContext() method that gives you access to the ServletContext.
Configure your Listener in your web.xml
You'll find additional info here : tutorial
Or on Sun's, er, Oracle's site.
By the way, if your file will be in a JAR file I am not sure that the ServletContext method is the best way to load it. I think you're better off with somethinbg like :
this.getClass().getClassLoader().getResourceAsStream("com.company.my.file.properties");
Related
I need to create a Rest endpoint dynamically in my Spring Boot application. Instead of statically creating the class with #RestController, is there a way to instantiate and activate a Rest service at runtime? It should be possible to specify the endpoint, input parameters etc at runtime.
Are there some Groovy options too?
Thanks,
Sandeep Joseph
I think the approach to take would be to create a custom MvcEndpoint that will handle all requests on a specific path, from there depending on your internal configuration you can process requests. It's basically just a Servlet (that's also an option). You're fully in control of the request.
public class MyEndpoint extends AbstractMvcEndpoint
// can optionally implements ApplicationContextAware, ServletContextAware
// to inject configuration, etc.
{
#RequestMapping("/dynamic-enpoints-prefix/**")
public ModelAndView handle(HttpServletRequest request, HttpServletResponse response)
throws Exception {
// here you have the request and response. Can do anything.
}
}
I have a resource class and I'd like to be able to check an authentication token before the resource method is called, thus avoiding having to pass the token directly into the Resource method.
I have added the following to web.xml:
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>com.michael.services.interceptors.AuthorisationInterceptorImpl</param-value>
</context-param>
My interceptor is implemented as follows:
#Provider
public class AuthorisationInterceptorImpl implements javax.ws.rs.container.ContainerRequestFilter {
#Inject
private ApiAuthenticationService apiAuthenticationService
#Override
public void filter(ContainerRequestContext requestContext) {
//Code to verify token
}
}
The filter method is being called before the methods in my resource class; however, the apiAuthenticationService is not being injected and is null when I attempt to call its methods.
I'm using Tapestry 5.3.7, Tapestry-Resteasy 0.3.2 and Resteasy 2.3.4.Final.
Can this be done ?
I don't think this will work, based on a quick glance at the tapestry-resteasy code.
The #Inject annotation is part of tapestry-ioc; if a class is not instantiated by Tapestry, the #Inject annotation is not honored.
Filters defined in web.xml are instantiated by the servlet container (Jetty, Tomcat, etc.) which do not have any special knowledge of Tapestry and Tapestry annotations.
I think you will be better off contributing a filter into Tapestry's HttpServletRequestHandler or RequestHandler pipelines (see their JavaDoc). I'm not sure how you can gain access to the ContainerRequestContext, however.
With tapestry-resteasy you don't need to define the provider in the web.xml file.
If you want to use Tapestry's autobuild mechanism just move your provider to the .rest package together with your resources.
If don't want to use autodiscovery/autobuild just contribute it to javax.ws.rs.core.Application
#Contribute(javax.ws.rs.core.Application.class)
public static void configureRestProviders(Configuration<Object> singletons, AuthorisationInterceptor authorisationInterceptor)
{
singletons.add(authorisationInterceptor);
}
Even though you can use rest providers for security is probably a good idea to take Howard's advice and implement your own filter in the tapestry pipeline.
BTW, you can also give tapestry-security a try :)
I have several services deployed as EJBs on a JBoss-AS-7.1 server. Many applications use these EJBs by doing a lookup like this:
#EJB(lookup = "java:global/FooService/FooBean!com.xyz.FooBeanRemote")
private FooBeanRemote fooBeanRemote;
The problem is that the lookup string is hard-coded in the source. I want to be able to change this lookup at runtime - without a re-compilation - because FooService may be updated some time in the future, and perhaps have a different implementation. In addition, the ejb could also move to a different server instance.
What would be the best way to achieve this?
Use ejb-jar.xml instead of annotation (check here)
use InitialContext in your code to lookup for bean and move bean name to properties file
Implement CDI producer methods in separate jar
--EDIT---
Quick HOWTO about last point:
1. Create qualifier
#Qualifier
#Retention(RUNTIME)
#Target({FIELD, TYPE, METHOD})
public #interface FooService {
}
2. Create producer method
public class EJBProducer {
#Produces
#FooService
#EJB(lookup = "java:global/FooService/FooBean!com.xyz.FooBeanRemote")
private FooBeanRemote fooBeanRemote;
}
3. Use in your code
#Inject #FooService
private FooBeanRemote fooBeanRemote;
Two first points may be in another jar archive (remember to include there META-INF/beans.xml file). You can also use producer method instead of field, and access ejb programmatically.
I am using JBoss 7.1 and Java 1.6.
I would like to integrate a Guice service with by JAX-WS endpoint. Using the interceptor pattern described by Gunnar.Morling I am able to properly instantiate the Guice modules when using a stateless bean as a webservice. However i am not able to do the same with a simple POJO annotated webservice. Is this possible has anyone found a workaround. Below is a summary of my efforts so far.
#UsesGuice #Interceptor
public class GuiceInterceptor {
#Inject
private GuiceInjectorHolderBean injectorHolder;
#AroundInvoke
public Object aroundAdvice(final InvocationContext ctx) throws Exception {
if (ctx.getTarget().getClass().isAnnotationPresent(UsesGuice.class)) {
final Injector injector = injectorHolder.getInjector();
injector.injectMembers(ctx.getTarget());
}
return ctx.proceed();
}
}
The GuiceInjectorHolderBean is the a sinlgeton bean responsible for triggering the guice wiring. The annotation class required follows
#Retention(RUNTIME)
#Target(TYPE)
#InterceptorBinding
public #interface UsesGuice {}
the JAX-WS POJO class
#UsesGuice
#WebService(serviceName = "EchoServiceService", portName = "EchoServicePort", ame = "EchoServiceImpl", targetNamespace = "lala")
public class EchoServiceImpl implements EchoService
{
#Inject
MyGuiceInjection injection;
#Override
#WebMethod
public String sayHello(final String msg)
{
return "Hello " + injection.call(msg);
}
}
Thanks in advance
Dimitri
Your Current Approach
In your code, javax.interceptor annotations #Interceptor, #InterceptorBinding and #AroundInvoke are supported by CDI and EJB standards and not by Guice. Guice uses proprietary AOP interception via org.aopalliance.intercept.MethodInterceptor interface and calling the method AbstractModule.bindInterceptor.
So you're trying to bootstrap Guice injection on your endpoint by:
using a non-Guice interceptor on the endpoint's method
within the #AroundInvoke method, programmatically invoking the Guice Injector, with injection target being the intercepted endpoint
That begs the Q, what to use for 1?
'Bootrap' Interception Mechanism for Your Current Approach
Obviously, an EJB interceptor works, as you've stated.
Other than an EJB or Guice AOP interceptor... an obvious alternative would be the standard, a CDI interceptor.
But that would make it all rather circular and heavy-weight... Why use CDI just to boostrap, so that you can configure and execute to your desired DI competitor: Guice?
Suggested Alternative Solution - JAX-WS Support for Manual Endpoint Instance Initialisation
If you want POJO web services, maybe consider back-tracking a bit, instead of interceptor-driven Guice initialisation, maybe this could be what you need:
javax.xml.ws.Endpoint.publish(String address, Object implementor)
Endpoint.publish javadoc
Initialise Guice in the standard way, use injector.getInstance() to construct your endpoint instance, and then use Endpoint.publish to set the endpoint instance against the port. The following gives a good example:
Using Guice 3 with JAX-WS in Java 6 outside web container
I have tried to use struts 1.3 API to make a small application with EJB 3.0. Unfortunatelly i cannot use the #EJB annotation to call my bean object from inside my action class. I have solved this problem using different workarounds ( the first one is to use my global jndi name of my bean and the other is to call another class first and use the #EJB annotation from that class). Still these two workarounds have significant disadvantages. I would like to call my EJB directly from my action class. I have read plenty examples using the "java:comp/env/beanName" JNDI name but still haven't figure out how to do it and get name not found axception.
Let the full name of the local EJB class be the com.ejb.myEjbPackage.MyEJBLocal, how can i call it using the context lookup? (can i do it without modifying any of the web.xml and sun-web.xml descriptors?)
I am using glassfish server and Netbeans IDE.
Thank you in advance
#EJB won't work in a standard pojo it can only be done in a managed object (i.e. another session bean)
So...
Here's your bean
#Stateless(mappedName="beanName")
public class beanName implements beanNameRemote {
Here's your lookup
Context context = new InitialContext(); //default lookup pulls from jndi properties file
context.lookup("beanName");
You can do some further reading on the mappedName to see if you want to use it or not.
I found the answer :
If you cannot use the EJB annotation in the class you want to call the bean then :
If you don't want to mess with XML descriptors to define your bean , you have to do it in the bean class itself.
Hence i used the following annotation in the GameBean class
#Stateless
#EJB(name="ejb/GameBean",beanInterface=GameBeanLocal.class,beanName="GameBean")
public class GameBean implements GameBeanLocal {.....
The beanName is optional. The annotation must be declared in the line ABOVE the declaration of the class.
Then, in order to call the bean from the other class you can do
InitialContext ic = new InitialContext();
ic.lookup("java:comp/env/ejb/GameBean");