New to REST - adding a web service class instance to a hashSet - java

I've been going through this tutorial and they added a web service class instance to a hashSet, like this:
public class MessageApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
public MessageApplication() {
singletons.add(new MessageRestService());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
I do not understand what the purpose of it is... I thought you could just access the web service with a URL

You made a class, this class is able to handle web requests. But this class has to be hosted somewhere. This means, this class has to be activated by a URL route. In this case you're using JBOSS.
In the first option of the tutorial, MKyong shows you how to configure RESTEasy Bootstrap (a bootstrap to load references) to map the URL with your class. This is done in web.xml and configures some kind of scanner that will map a certain URL with your class.
The second option is not using RESTEasy Bootstrap and you have to add your class to a collection of long living objects in your application manually. This is done defining the Application (MessageAplication) and defining it in the web.xml.

Yes, you can access the webservice via a URL, but the server needs to know what to do with calls to a certain URL.
Yours is one way (the bootstrap version) of telling the application server where to look for JAX-RS resources: http://www.mastertheboss.com/resteasy/resteasy-tutorial (Step #4)
There is a (newer) alternative, depending on which server and RESTeasy-version you use, which relies on autoscanning for certain annotations. For RESTeasy on JBoss, it's described at the bottom of the tutorial-page I linked.

Related

Register context listener for jersey

I need to perform some clean up steps after shutting down a jersey server. To my mind this could be easily accomplished by implementing a ServletContextListener. The question of course is how to add this listener to the application. I have seen examples where this is done in the file web.xml like this:
<listener>
<listener-class>org.SomeCompany.SomePackage.server.MyListener</listener-class>
</listener>
where the MyListener class looks as follows:
#WebListener
public class MyListener implements ServletContextListener {
The problem is that this approach only works for deployment as a war file. However, I do also ship my software as a standalone jar file which creates a Grizzly web server to deploy the servlet:
HttpServer httpServer = GrizzlyHttpServerFactory.createHttpServer(BASE_URI,
new MyServerConfig());
The class MyServerConfig subclasses from ResourceConfig and uses the various register methods. I would like to add the listener programmatically as well, but calling register doesn't seem to do the job. Any ideas how to fix this?
The first thing you are going to need to configure Grizzly as a servlet container. This is not the default behavior. You are only creating an HTTP Server. So the first thing you will need to is Grizzly servlet dependency
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<version>${jersey2.version}</version>
</dependency>
So here's the deal with this. With this artifact, instead of the Grizzly HttpServer with GrizzlyHttpServerFactory, you would instead use the GrizzlyWebContainerFactory. The only thing is, if you look though the factory API methods, there really isn't a place to register any listeners, and from what I tested, the #WebListener annotation will not automatically get picked up. What we need access to is the Grizzly WebAppContext that Jersey uses to create the Grizzly servlet container.
The way I was able to get it to work, was just to grab some code from the GrizzlyWebContainerFactory.create source code, and just create the container myself. It's really not much code. Most of the source code does checks as it needs to be universal. But in a single use case (with no init-params), you can pretty much cut the code down to this
private static HttpServer create(URI u, Servlet servlet) throws IOException {
String path = u.getPath();
path = String.format("/%s", UriComponent.decodePath(u.getPath(), true)
.get(1).toString());
WebappContext context = new WebappContext("GrizzlyContext", path);
context.addListener(MyListener.class);
ServletRegistration registration;
registration = context.addServlet(servlet.getClass().getName(), servlet);
registration.addMapping("/*");
HttpServer server = GrizzlyHttpServerFactory.createHttpServer(u);
context.deploy(server);
return server;
}
Then just call HttpServer server = create(BASE_URI, new ServletContainer(resourceConfig));
As an aside, for your use case (I just re-read the question :-), Jersey also has Event Listeners. You can write an ApplicationEventListener and listen for the destroy event, and do all your processing there.

Is there a SelfAttachingServerResource for Restlet?

I'm trying to create a Framework on top of Restlet and my question would be, is it possible to have a ServerResource to be "injected" from outside the org.restlet.Application code?
The standard way is to have a resource injected here:
public class FrameworkApplication extends Application {
private static final String ROOT_URI = "/";
/**
* Creates a root Restlet that will receive all incoming calls.
*/
#Override
public Restlet createInboundRoot() {
Router router = new Router(getContext());
router.attach(ROOT_URI, RootServerResource.class);
return router;
}
}
However since I am building a framework the use of FrameworkApplication is through including it as a dependency:
<dependency>
<groupId>com.mycompany</groupId>
<artifactId>myframework</artifactId>
<version>0.0.1</version>
</dependency>
Going back to the question, I want to know if it is possible to have a ServerResource to be added in the Restlet routing like this:
public class PluggableResource extends ServerResource {
#Get("json")
public String represent() {
// stuff
return resp;
}
}
In the case of dependency injection, the solution was to do, SelfInjectingServerResource now can I make such a SelfAttachingServerResource?
I don't know what you exactly want to do but auto-discovering support of server resources isn't supported in Restlet. You need to implement by your own within a dedicated implementation of the class Application of Restlet. The method createInboundRoot would be responsible to scan the classpath to detect server resources. Moreover you need to add more metadata for server resources (with annotations for instance) to specify the attachement path.
However, the JAX-RS support provides this feature. It provides a set of annotations to make easy to identify server resources and provide metadata like attachement path, methods and exchanged media types for methods. Here is a sample of use: http://restlet.com/technical-resources/restlet-framework/guide/2.3/extensions/jaxrs. The classes for server resources need to be register by hand but you can go further. As a matter of fact, you can scan the classpath to detect classes having the annotation Path. See this link for the way to implement such ferature: Scanning Java annotations at runtime. In this case, they will be autodetected based on annotations. Is something can suit your needs?
Hope it helps.
Thierry

How can annotations be added to dynamic proxy classes in Java?

I am trying to create a dynamic proxy that would wrap an EJB around a web service because the application server does not support creating an EJB based web service without a proprietary router project generation.
My thought was to create a dynamic proxy, and some how just start it using an InitServlet. Right now I am kind of stuck on figuring out how to set the annotations dynamically so that I won't get the following error.
class $Proxy0 has neither #WebSerivce nor #WebServiceProvider annotation
at com.sun.xml.internal.ws.server.EndpointFactory.verifyImplementorClass(EndpointFactory.java:277)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.getPrimaryWsdl(EndpointImpl.java:273)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.createEndpoint(EndpointImpl.java:213)
at com.sun.xml.internal.ws.transport.http.server.EndpointImpl.publish(EndpointImpl.java:143)
Recently I have had the same problem. It seems that most people say is not possible. See http://softwarecarnival.blogspot.be/2009/02/java-annotations-and-proxies.html
If the interface that you have is:
interface XXXInterface{
Result doStuff1(String param1)
}
then a workaround is to create a delegator to the proxy that will also implement the web service.
#WebService
public class WebServiceDelegateToXXXServer implements XXXInterface{
public WebServiceDelegateToXXXServer(XXXInterface actualImplementor){
this.actualImplementor = actualImplementor;
}
public Result doStuff1(String param1){
return actualImplementor.doStuff1(param1);
}
}
Then you will publish
XXXInterface proxy = createProxyAsXXXInterface();
Endpoint.publish(url, new WebServiceDelegateToXXXServer(proxy));

JavaEE6+REST: How do I get all REST resources at runtime?

Is there a possibility to get a list of all registered REST resources at runtime?
With REST resources I mean:
either classes which have annotations such as #Path(...) and are considered by the server at runtime (so traversing all classes using reflection would not do),
or URIs of all paths (REST class can have multiple paths).
NOTE 1: I am using automatic configuration (that new feature of JavaEE 6) and Netbeans just generates an empty ApplicationConfig class.
NOTE 2: Using Netbeans 6.9, JavaEE 6, Glassfish 3. Is more information on my ecosystem needed?
Are you using Jersey? If so, then a WADL is generated automatically at /application.wadl. The WADL contains a lot of information about registered resource paths.
See also: WADL Support
public synchronized Response doSomething(#Context Application c, #FormParam("someParam") String someParam)
throws Exception {
// gives a list of classes which are used by this Jersey instance
// and have REST-related annotations
c.getSingletons(); // returns Set<Object>
return something;
}

Sharing a static object between a servlet and a webservice

I have a servlet which handles http get requests that I'd like to be able to share an object which is also used by a webservice im developing. They are both on the same tomcat server within the same web-app container. Im not sure best how to do it any ideas ?
You can share things across the webapp by storing them as attributes in the ServletContext (using setAttribute / getAttribute). You could create the object in an impelementation of ServletContextListener, store it in the ServletContext, and then retrieve it and use it from your web service and servlet.
I will expand on my comment here.
In the simplest case ServletContext.setAttribute/getAttribute would be fine. But some people rightly raised the questions about thread safety.
For this a better approach would be to store a shared POJO in a ServletContext during webapp initialization and get it wherever you need with ServletContext.getAttribute.
For this you need to implement ServletContextListener interface and declare it in your web.xml file.
<listener>
<listener-class>your.package.ServletContextListenerImpl</listener-class>
</listener>
This listener is called once when your webapp is loaded by the servlet container, and when it is about to be unloaded by the servlet container. In both cases it passes ServletContextEvent that has a handle to ServletContext. It is at that point that you want to set/removeAttribute that points to your shared object.
Because of this you may be certain that ServletContext.getAttribute will return a valid object when called from the Servlet.service or one of the do... methods.
As for attribute name, I would go with your Shared class classname. I would also add a static access method to your shared class to get it from the ServletContext, like this:
public class Shared
{
...
public static Shared fromServletContext ( final ServletContext context )
{
return (Shared) context.getAttribute( Shared.class.getName( ) );
}
}
The simplest option is create a Singleton - a class which allows only one instance in memory. Since you get it by calling a static method on the class itself it should be available to both the servlet and the WS
If my alternative understanding of the question is correct, the data which comes from request should be stored, and then retreived by the web-service. If this is supposed to run in a multi-user environment, you might consider using an in-memory database (HSQLDB) to temporarily store the data. Then you will be able to retrieve it with your web-service, based on some criteria I cannot foretell.
If this is application-specific data (accessible by all users (sessions)), then use ServletContext#set/getAttribute(). If this is user (session)-specific data, then use HttpSession#set/getAttribute().
Let the servlet class set the object in the desired scope (application or session) by a specific attribute key and let the webservice get the object from the desired scope by the same attribute key.
I think you rather need the HttpSession.
The singleton story makes no sense here.

Categories