REST WebServise - how to use service like a singleton? - java

My rest application contains a service and I need to make this service to act like a singleton to save a state of the service.
a service:
#Path("/script")
public class ScriptEngineProvider {
private AtomicInteger idCounter;
public ScriptEngineProvider() {
System.out.println("before AtomicInteger");
idCounter = new AtomicInteger();
}
#POST
public Response executeScript( String x ) {
idCounter.incrementAndGet();
System.out.println("counter " + idCounter);
...
a client besides all other code has:
WebTarget webTarget = client.target("http://localhost:8080/NashornEngine/rest").path("script");
web.xml
<url-pattern>/rest/*</url-pattern>
With the above configuration the application works but with every request the variable idCounter creates so idCounter is allways 1.
Now I use next class to make the ScriptEngineProvider to be a singleton:
#ApplicationPath("/services")
public class NashornApplication extends Application {
private Set<Object> singletons = new HashSet<Object>();
public NashornApplication() {
singletons.add(new ScriptEngineProvider());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
}
The problem is that I get The requested resource is not available with request:
//path services was added
WebTarget webTarget = client.target("http://localhost:8080/NashornEngine/rest").path("services").path("script");
What is the problem with this config?

try this:
#Singleton // this is the important line
#Path("/script")
public class ScriptEngineProvider {
private AtomicInteger idCounter;
public ScriptEngineProvider() {
System.out.println("before AtomicInteger");
idCounter = new AtomicInteger();
}
#POST
public Response executeScript( String x ) {
idCounter.incrementAndGet();
System.out.println("counter " + idCounter);
...

#ApplicationPath effectively serves the same purpose as the url-mapping. But only one can be used. You use #ApplicationPath with an Application subclass when you don't want to use web.xml configuration. To go web.xml-less, you need to make sure of two things
You are deploying to a 3.x servlet container.
You have the dependency that supports the servlet pluggability. See more here
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey2.version}</version>
</dependency>
It's also possible to use an Application subclass without the #ApplicationPath, which will then use the url-mapping to map the Jersey servlet. For example
<servlet>
<servlet-name>MyApplication</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.pkg.YourApplication</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
Which ever way you choose, either the url-mapping path will be used, or the #ApplicationPath value will be used, but not both. So in your case, if you do with no web.xml configuration, the path would not include the /rest in the url-mapping. And if you go with the above web.xml configuration, then you should get rid of the #ApplicationPath on your Application subclass, that url you would use would with /rest, with no /services.
The reason you keep getting one is because
The default behavior is to create a new resource class for every request
Your Application subclass is not being used, and your web.xml configuration is being used, where you are package scanning.
Review the information from this post, and make the changes accordingly.

Related

tomcat jersey retrieve full context path

I'm implementing ApplicationEventListener, I need to retrieve the context path, the one declared in my web.xml:
<servlet-mapping>
<servlet-name>MyApplication</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
I'm implementing onEvent method
#Override
public void onEvent(ApplicationEvent event) {
if (event.getType() == ApplicationEvent.Type.INITIALIZATION_FINISHED) {
final ResourceModel resourceModel = event.getResourceModel();
}
}
I can also use #Context ServletContext servletContext in ResourceConfig to pass the info if necessary but I don't know how to reach this.
From a servlet using HttpServletRequest, it's possible to call request.getContextPath(), but obviously I can't use HttpServletRequest.
Generally speaking, in my application I need a way to retrieve servlet-mapping
Thanks
Edit:
listener class: org.glassfish.jersey.server.monitoring.ApplicationEventListe‌​ner

Spring MVC request mapping conflict

I'm having an issue regarding #RequestMapping on classes. Say I have these two controllers:
#Controller
#RequestMapping(value="/controller1")
public class Controller1 {
#RequestMapping(value="/method11.do")
public #ResponseBody method11(){
//...
}
#RequestMapping(value="/method12.do")
public ModelAndView method12(){
//This method redirects me to another jsp where I'll call Controller2 methods
return new ModelAndView("test");
}
}
#Controller
#RequestMapping(value="/controller2")
public class Controller2 {
#RequestMapping(value="/method21.do")
public #ResponseBody method21(){
//...
}
}
When I first call via AJAX method11, it works fine, the url generated is http://mydomain/myapp/controller1/method11.do
Then, I call method12 and get redirected to test.jsp, and from there, I call to method21, and here is the problem, the url generated is not the expected http://mydomain/myapp/controller2/method21.do, but something else, depending on how I make the AJAX call:
url:'controller2/method21' --> http://mydomain/myapp/controller1/controller2/method21.do
url:'/controller2/method21' --> http://mydomain/controller2/method21.do
So, in what way should I make the calls so that they always start at http://mydomain/myapp/...?
I believe I could just use url:'/myapp/controller2/method21.do', but I guess there should be a more generic way in which I don't have to use 'myapp' on every call.
This is my web.xml:
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
You should make the client aware of the proper URL by retrieving the context root within your script using JSP EL.
In JSP
<script>var ctx = "${pageContext.request.contextPath}"</script>
You can then use ctx as a prefix to the URLs constructed via Javascript.
var url = ctx + "/rest_of_url"
On the server side, you can use:
${pageContext.request.contextPath} or JSTL has a tag, <c:url> which will append your context root.

Java RESTful Web Service - Annotate an Interface instead of a Class

I am trying to setup a simple web service (deploy on tomcat) which goes like this:
#Path("/api")
public interface Api {
#GET
#Path("categ")
public String getCateg();
}
and I have the following class implementing the interface:
public class RAPI implements API {
public String getCateg() { ... }
}
My web.xml looks as follows:
<servlet>
<servlet-name>API</servlet-name>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>com.sun.jersey.config.property.packages</param-name>
<param-value>com.api.resources</param-value> <!-- THIS IS CORRECT -->
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>API</servlet-name>
<url-pattern>/api/*</url-pattern>
</servlet-mapping>
But when I try to deploy on Tomcat I get the following (rather expected error):
com.sun.jersey.api.core.ScanningResourceConfig init
INFO: No provider classes found.
Which (not copied the whole trace here) tells me that although it found the API interface it cannot instantiate it.
How can I declare which of the implementing classes will actually act as the REST web service?
Having an interface annotated with JAX-RS allows you to create remote proxy clients. We do this with Apache CXF, but I haven't tried it with Jersey.
EG in my Spring config I can have;
<jaxrs:client id="myClient" inheritHeaders="true"
address="http://myhost/rs"
serviceClass="com.mycorp.restful.MyServiceInterface">
<jaxrs:headers>
<entry key="Accept" value="application/xml"/>
</jaxrs:headers>
</jaxrs:client>
I can now use this spring bean by just calling the methods. I don't have to create a Client and I don't have to care about the relative paths of the different RS services it defines.
As for using Interface for REST Service it is a good idea IMHO. But one thing do not annotate Interface itself leave it for implementation. This way you may have more flexibility. For instance,
public Interface Readable {
#GET
#Path("/read/{id}")
public String read(#PathParam("id") Integer id);
}
#Service
#Path("/book")
public class Book implements Readable, ... {
...
public String read(Integer id){...}
}
As for Jersey proxy check this:
https://jersey.java.net/project-info/2.0/jersey/project/jersey-proxy-client/dependencies.html

GWT + GAE Servlet URL and Servlet Mapping

http://127.0.0.1:8888/socialnetwork/contactsService
That's the current URL for one of my servlets. My question is, how do I change it?
In my web.xml file, altering
<servlet-mapping>
<servlet-name>contactsServiceServlet</servlet-name>
<url-pattern>/socialnetwork/contactsService</url-pattern>
</servlet-mapping>
to
<servlet-mapping>
<servlet-name>contactsServiceServlet</servlet-name>
<url-pattern>/a/contactsService</url-pattern>
</servlet-mapping>
Makes absolutely NO difference to the URL it requests when I make an RPC-call to the servlet.
Once you have done the above you need to change where you invoke (Which is described in the Annotation below) as in...
// The RemoteServiceRelativePath annotation automatically calls setServiceEntryPoint()
#RemoteServiceRelativePath("email")
public interface MyEmailService extends RemoteService {
void emptyMyInbox(String username, String password);
}
See http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/rpc/RemoteServiceRelativePath.html

Modify Servlet parameters

I've a GWT Servlet running in a Tomcat 6.0 server. This server acts as a proxy to another service. This final service may be running in different IPs and/or ports in my network.
How can I configure my GWT Servlet to connect to any of my services without manually modifying the web.xml file?
I'm initializing my servlet with:
<!-- Servlets -->
<servlet>
<servlet-name>MyServlet</servlet-name>
<servlet-class>com.proxy.MyServletServiceImpl</servlet-class>
<init-param>
<param-name>serverAddress</param-name>
<param-value>192.168.1.10</param-value>
</init-param>
<init-param>
<param-name>serverPort</param-name>
<param-value>55005</param-value>
</init-param>
</servlet>
From inside my MyServletSerciveImpl.java file I'm doing
private void loadConfig() {
ServletConfig config = this.getServletConfig();
serverAddress = config.getInitParameter("serverAddress");
serverPort = Integer.valueOf(config.getInitParameter("serverPort"));
}
My ideal case would be that this configuration is the default, but applying some configuration file (a properpies file, xml, ini, cfg, .....) I could overwrite the default web.xml values.
Any idea how to do that?
Thanks.
For true dynamic configuration, you can expose a configuration object as a jmx bean, and have your servlet use that bean.
An intermediate solution is to put the configuration in a different file, as xml or properties, or in a db table, and read from it periodically in a background thread.
For completeness:
public class MyServiceImpl extends RemoteServiceServlet implements
MyService {
private void loadConfig() {
InputStream inStream = this.getServletContext().getResourceAsStream("/WEB-INF/config.properties");
Properties properties = new Properties();
try {
properties.load(inStream);
// properties.getProperty("myValue");
} catch (IOException e) {
Log.error(e.getMessage());
e.printStackTrace();
}
}
....
}

Categories