How do paths work in a Java deployed REST web service? - java

Under Tomcat and Jersey libraries I created a REST web service described in this class:
package Servicios;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Consumes;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.Produces;
#Path("service")
public class ServiceResource {
#Context
private UriInfo context;
/**
* Creates a new instance of ServiceResource
*/
public ServiceResource() {
}
#GET
#Produces("text/html")
public String getHtml() {
return "<h1>Here we are, at the contemplation of the most simple web service</h1>";
}
#PUT
#Consumes("text/html")
public void putHtml(String content) {
}
}
So, as I set it before accessing to http://localhost:8080/GetSomeRest makes the default created .jsp file created.
I set in project propierties (using NetBeans) a relative URL as webresources/service, so service part is same defined in #Path("service"). All works ok, going to http://localhost:8080/GetSomeRest/webresources/service makes the web service be consumed.
But what if I want to consume that service right from http://localhost:8080/GetSomeRest/service? I tried to set only service in such relative URL and I got an Error 404 message going to http://localhost:8080/GetSomeRest/service
How do virtual paths work?
What would it mean to add an alias to a web service?

The path segment webresources is not set in the code you provide so I will guess what your code looks like.
A JAX-RS application can be configured with a class extending javax.ws.rs.core.Application. Such a class can be annotated with #javax.ws.rs.ApplicationPath(). My guess is that in your project this annotation is set to
#javax.ws.rs.ApplicationPath("webresources")
So the URL of a JAX-RS resource class is build from these parts.
http://localhost:8080/ - host and port
GetSomeRest - the context, normally the name of the deployed .war file
webresources - the value of the #ApplicationPath annotation
service - the value of the #Path annotation of the class
I recommend not to skip step 3.
The value of the #ApplicationPath annotation can be overridden by a servlet-mapping element in the web.xml.

Just for information
The path segment webresources
is set in the code by netbeans in the package
org.netbeans.rest.application.config - ApplicationConfig Class into your own project!!! so change it and it's done...

Related

Debugging SpringBoot MVC service application 404 error

A web application I've been working on recently the past like 2 weeks maybe for whatever reason when I finally tested it - won't seem to even enter the method that I have to return a JSON list of objects. I have included the Jackson library and Spring Boot Web, Tomcat, Data-JPA, Hibernate, MySQL, and a library to allow me to access JSP files. The index.jsp comes up but I almost feel like Spring Boot is giving me that free of charge as it's not even entering that method. I have been having the issue for a few days but trying to resolve it on my own - I found another answer that suggested to put a breakpoint inside one of the Spring classes but when I "debugged" it through Eclipse, it didn't even stop at that class - something about pattern matching - One answer suggested adding a context to the application.properties file - didn't help. I've reduced it to as simple as I think I can get it. Can anyone tell me what I might be doing wrong? Before my code, the project is on Github at: https://github.com/sfulmer/Scheduler.git
Here's my controller:
package net.draconia.schedule.controllers;
import java.util.List;
import net.draconia.schedule.beans.Event;
import net.draconia.schedule.dao.EventDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class ScheduleController
{
private static final Logger logger = LoggerFactory.getLogger(ScheduleController.class);
#Autowired
private EventDAO mObjDAO;
protected EventDAO getDAO()
{
return(mObjDAO);
}
//#GetMapping("/events")
#RequestMapping(value = "events", method = RequestMethod.GET)
public #ResponseBody List<Event> getEvents()
{
logger.debug("I got here");
return(getDAO().getList());
}
#GetMapping("/")
public String index()
{
return("index");
}
}
Here is the DAO interface - I'll show the class if necessary but this is what the controller looks at:
package net.draconia.schedule.dao;
import java.util.List;
import javax.persistence.EntityNotFoundException;
import net.draconia.schedule.beans.Event;
public interface EventDAO
{
public Event getEventById(final long lId) throws EntityNotFoundException;
public List<Event> getList();
public void remove(final Event objEvent);
public void removeById(final long lId);
public Event save(final Event objEvent);
}
The Event class is so long but if I need to include it, I will. The application.properties file is here:
spring.datasource.url = jdbc:mysql://localhost:3306/schedule
spring.datasource.username = root
spring.datasource.password = R3g1n# M1lL$ 1$ My Qu3eN!
spring.mvc.view.prefix: /WEB-INF/jsp/
spring.mvc.view.suffix: .jsp
server.servlet.contextPath=/scheduler
and here is my Application class(with the SpringBootApplication annotation):
package net.draconia.schedule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
#SpringBootApplication(scanBasePackages = {"net.draconia.schedule.controller"})
public class ScheduleApp implements WebMvcConfigurer
{
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder)
{
return(builder.sources(ScheduleApp.class));
}
public static void main(String[] args)
{
SpringApplication.run(ScheduleApp.class, args);
}
}
I'm relatively new to Spring Boot but haven't ever ran into this problem ever before as I work with it at work and it works fine but we use entirely REST services there and I am using JSP files as well as sorta end-points that respond with JSON but you can't respond from REST services with JSP views so unfortunately I can't copy work's project to get that working or I would sigh Any thoughts on how I can get this working or what I am omitting?
My guess is that you're mixing things from Spring and Spring boot, and that's getting problems on loading beans, as you're probably changing the annotations load order or loading other beans rather than spring boot defaults as expected. For example, you implements WebMvcConfigurer, but you aren't providing any WebMvc Configuration, like a ViewResolver bean
My advice is to follow this guide: https://spring.io/guides/gs/spring-boot/
and use only the annotations from spring boot if using spring boot, or spring if using spring (they're similar, but not exactly the same, configuration is different).
Anyways, you can check loaded beans in Spring application context (Inject it in Application class) with ctx.getBeanDefinitionNames() method and see if your controller is there (i guess not).
By looking into code, my first impression is that, you have some typo in here:
#SpringBootApplication(scanBasePackages = {"net.draconia.schedule.controller"})
Your controller class package name has net.draconia.schedule.controllers.
So can you please correct your scanBasePackages with proper package name.
If that is not the case, please update full stack trace along with GET request which you are submitting into application. Will take a look & update answer accordingly.

#RolesAllowed etc. without web.xml

I am currently working on a quite modular application where we have many jars that will be packaged and glued together in a war file.
Some of these jar files have REST resources that want to be secured. Common way is the #RolesAllowed annotation etc.
From my current knowledge this implies an existing web.xml in the WAR. This way we would have to implement jar-specific information (e.g. context roots) inside the WAR, not in the place where it belongs.
Like the most things nowadays - is there a way to programmatically set up security contexts etc. without a web.xml?
You can restrict access to your REST resources by registering RolesAllowedDynamicFeature in your REST configuration class that extends from ResourceConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
super(ApplicationConfig.class);
register(RolesAllowedDynamicFeature.class);
}
}
So you can use your application roles on your resources methods like this
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.SecurityContext;
#Path("secured")
#PermitAll
public class SecuredResource {
#GET
#Path("user")
#RolesAllowed("user")
public String user(#Context SecurityContext sc) {
boolean test = sc.isUserInRole("user");
return (test) ? "true": "false";
}
#GET
#Path("admin")
#RolesAllowed("admin")
public String admin(#Context SecurityContext sc) {
boolean test = sc.isUserInRole("admin");
return (test) ? "true": "false";
}
}
Jersey documentation has more details on securing REST resources using annotations here
https://jersey.github.io/documentation/latest/security.html#d0e12428
I've not worked with JAX-RS for a while, but the last time I checked, when using annotation-based security, web.xml is not optional.
See my answer for details.
https://stackoverflow.com/a/20023018/839733

in jersey 2.x am getting the error like java.util.concurrent.ExecutionException

i have used the jersey implementation of a jaxrs but iam unable to the programme following is case where i am getting problem any idea help me
in following programme i used the jersy 2.x implementaion of jaxrs
i implemented the programme using jersey implemetation of jax-rs(restfull)
2 classes i have written instead of web.xml i used the class
MyResource.java
package com.rest.application;
import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import com.rest.webservice.SampleService;
#ApplicationPath("rest")
public class MyResource {
private Set s;
public MyResource() {
s=new HashSet();
s.add(new SampleService());
}
public Set getSingletons() {
return s;
}
}
SampleService.java
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
#Path("sample")
public class SampleService {
#GET
#Produces("text/html")
#Path("{username}")
public String sayHello(#PathParam("username")String s) {
return "<font color='blue' size=8>Hello:" +s+ "</font>";
}
#GET
#Produces("text/plain")
public String sayBye() {
return "Bye";
}
}
i added the all jars needed to this programm
still i am getting following error
java.util.concurrent.ExecutionException:
org.apache.catalina.LifecycleException:
Failed to start component [StandardEngine[Catalina].
StandardHost[localhost].StandardContext[/RestApp2]]
Caused by: org.apache.catalina.LifecycleException:
Failed to start component [StandardEngine[Catalina].
StandardHost[localhost].StandardContext[/RestApp2]]
like this same error is displaying everywhere
when i changed the server tomcat 7 to 6
it is working but not displaying the output
will anybody have any idea thanking you in advance
This says, #ApplicationPath("rest") may be applied only to the subclass of Application.
Can you share more on what are you trying to do and what is the complete stack trace. Are you using web.xml ?
As #MSD mentioned, your use of #ApplicationPath is incorrect. See the Jersey documentation on Application Deployment to see all the different deployment options, and how they work in different environments.
Basically, the easiest way put the #ApplicationPath on an empty Application class
#ApplicationPath("/rest")
public class MyApplication extends Application {}
This will scan the entire classpath for #Provider and #Path annotated classes, to register with the application. Though this may seem easier, the more common approach, when working with Jersey is to use it's ResourceConfig class, which is a subclass of Application. You can register packages, which will scan the packages and subpackages
#ApplicationPath("/rest")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("com.my.packages");
}
}
One benefit is that sometimes there will be third party dependencies that are annotated, but you don't want registered. To register individual classes just use register(...class) in the ResourceConfig.
Now the reason for the error in Tomcat 7 and not 6, is most likely because Tomcat 6 (servlet 2.5) does not have the sevlet pluggability mechanism, which uses the ServletContainerInitializer. The Jersey implementation of this initializer loads the application, looking for the #ApplicationPath on the Application subclass. If you're not in a 3.0 environment, this functionality will not work.
Note the Jersey initializer is included in the jersey-container-servlet jar. You can read more about it here

JAX-RS Resource not found in GlassFish Server

I've been trying to create a simple Restful WebService, using NetBeans Ide.
My Java EE Version is: Java EE 7 Web.
I created a new Java Web Application, setting this ContexPath: /DukesAgeService.
Now, running my application, browser display my Index.html page at:
http://localhost:8080/DukesAgeService/
so, everything works fine.
Then, I tried to create a simple restful resource using the RESTful Web Service Wizard.
So, I created this class:
package firstcup.webservice;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PUT;
/**
* REST Web Service
*
* #author nolanof
*/
#Path("dukesAge")
public class DukesAgeResource {
#Context
private UriInfo context;
/**
* Creates a new instance of DukesAgeResource
*/
public DukesAgeResource() {
}
/**
* Retrieves representation of an instance of firstcup.webservice.DukesAgeResource
* #return an instance of java.lang.String
*/
#GET
#Produces("text/plain")
public String getText() {
return "hello world";
}
}
But running my application, at url:
http://localhost:8080/DukesAgeService/dukesAge
I get a 404-not found page.
I exptected that any incoming get request that has the url of "/dukesAge" was handled by DukesAgeResource class getText method. Whats' wrong?
Thanks
You're probably missing the JAX-RS application servlet. You can either define it in the web.xml or if you want to go xml-less, you can use an Application subclass. The easiest way IMO is just to use the Application subclass annotated with #ApplicationPath. A servlet will be created and the servlet path will be set to the value in the annotation. Something like
#ApplicationPath("/rest")
public class RestApplication extends Application {
// All request scoped resources and providers
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<>();
classes.add(DukesAgeResource.class);
return classes;
}
// all singleton resources and providers
#Override
public Set<Object> getSingletons() {
Set<Object> singletons = new HashSet<>();
return singletons;
}
}
Then the resource should be accessed via
http://localhost:8080/DukesAgeService/rest/dukesAge.
There are other ways, but this is the portable way. Glassfish uses Jersey, but creating a Java EE web application from scratch in Netbeans will only import compile time Java EE standard classes (no Jersey dependencies). So the above is really your best bet to start off with.
You can see other deployment options at the Jersey Documentation. For some of the options, you may need to add some Jersey compile-time dependencies. That's why I just mentioned the above. No other jars needed.
Another thing that would cause a 404, is if you specify the JAX-RS servlet path as /*. This will conflict with the default servlet that serves the static resources like your html pages. That's why I set it to /rest.
UPDATE
It is also stated in the JAX-RS spec that if there are empty sets returned in the getClasses() and getSingletons(), implicit classpath scanning should occur. (provider) Classes annotated withe #Provider will by default be added as singletons and resource classes annotated with #Path will be per-request objects (meaning a new object is created each request). So you could alternatively just have
#ApplicationPath("/rest")
public class RestApplication extends Application {
// Left empty
}
and it should work just the same.
You may have initialized some path in your web.xml, probably that is why you are getting a 404 error while you call the service. Do check your web.xml and in case it is set to anything rather then * then please append that to your service call to get it working.

How Can I store a XML object in a global session that can be reached every request?

Every night a XML document comes in a folder in the WS server.
I want the web service to read this XML file at a certain time (let's say at 05:00) and place it in a object stored in memory, every day.
How can I achieve this? Which object should I use?
I intend to use a JAX-WS. Could it be possible using JAX-RS too?
Tks.
You can store it as an attribute in the ServletContext of the application. It will be accessible to any JAX-WS services or JAX-RS resources in the web module. As an added bonus, if your JAX-WS service and JAX-RS resources are in the same module (war), they will share the same instance of the object/document you place there.
For the JAX-RS resource:
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.servlet.ServletContext;
#Path("myresource")
public class MyResource {
#Context ServletContext context;
#GET
#Produces("text/plain")
public String getMyResource() {
return context.getAttribute("cachedDocument");
}
}
For the JAX-WS service:
import javax.jws.WebService;
import javax.jws.WebMethod;
import javax.annotation.Resource;
import javax.servlet.ServletContext;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;
#WebService
public class MyService {
#Resource
private WebServiceContext context;
#WebMethod
public String getDocument() {
ServletContext servletContext =
(ServletContext) context.getMessageContext().get(MessageContext.SERVLET_CONTEXT);
return servletContext.getAttribute("cachedDocument");
}
}
See also: ServletContext javadocs.

Categories

Resources