I have developed a webservice in Java that runs as a servlet on a tomcat, parameters for the application are given to the servlet via the get request (e.g. servlet?method=search&query=searchterm123), the servlet recognizes if the method and the query are defined and in the case of an error gives back a string that is manually wrapped in xml code that I hardcoded via this.writer.println(answer);. If the method is right a new class is instantiated which does the search and then gives back an object which XStream converts into XML for me which I then again send back to the client with println wrapped into my xml overhead that is again hard coded String answer ="<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n".
Obviously this works and also very efficiently but this is far from elegant. I have looked into Apache CXF very briefly and also into things like RESTlet or JBOSS RestEasy, the latter two I found to much for my demands. Every tutorial I find on CXF always includes Spring and Maven which then overwhelms me a little. Do you have suggestions how I should turn my dirty hack into a pretty application?
I think using a JAX-RS framework (as CXF and Resteasy, but also Jersey) is the way to go in your case. Regarding serializing to XML, maybe have a look at JAXB (as included in Jersey too for instance). It should help automatically serialize any entity structure.
Regarding the complexity of such application: it should always depend on what infrastructure you use. If its just a simple Java EE server, its possibly best to use the implementation of that vendor (Jersey for Glassfish, Resteasy for JBoss). Otherwise, just use the build system you are familiar and comfortable with. You can easily replace the Maven dependencies with Ant and Ivy for example.
I can recommend CXF; I found it extremely easy to get going with its tutorial, especially once I bit the bullet and used Maven to manage dependencies (though really it's orthogonal to everything that CXF and Spring do).
But in order to make use of CXF I really recommend using Spring. You don't have to use all of Spring; the simple tutorial on the CXF site gives you enough to get going. This is especially true if you've already got the code that actually implements things already done, and separated out from the code to parse incoming URLS, render responses as XML, etc.; that's the part that CXF (and typically JAXB) will handle for you.
To help, here's a mega-simple example (with imports omitted for brevity).
I know it looks complicated, but almost all the second half consists of stuff you write once and then don't really touch again; as you build out to tackle your real code, you can do a lot without paying must attention to the framework code at all.
First, the interface definitions (including the XML type model):
public interface Foo {
#Path("/") #GET #Produces("application/xml");
FooDesc getDescription(#Context UriInfo ui);
#Path("{id}")
FooItem getFoo(#PathParam("id") String id);
}
#Path("/")
public interface FooItem {
#GET #Produces("application/xml")
FooItemContents getContents();
#PUT #Consumes("application/xml")
void setContents(FooItemContents desc);
#DELETE
Response delete();
}
// These classes are purely structural holders; no behavior.
#XmlRootElement #XmlType
public class FooDesc {
#XmlElement
public List<URI> foo;
}
#XmlRootElement #XmlType
public class FooItemContents {
#XmlElement
String bar;
}
Next, the implementation class:
public class FooImpl implements Foo {
public FooDesc getDescription(UriInfo ui) {
FooDesc desc = new FooDesc();
desc.foo = new ArrayList<URI>();
UriBuilder ub = ui.getAbsolutePathBuilder().path("{id}");
for (String id : realGetIdList()) // Hook to your code here!
desc.foo.add(ub.build(id));
return desc;
}
public FooItem getFoo(String id) {
final RealFoo r = realGetById(id); // Hook to your code here!
return new FooItem() {
public FooItemContents getContents() {
FooItemContents contents = new FooItemContents();
contents.bar = r.getBar(); // Hook to your code here!
return contents;
}
public void setContents(FooItemContents desc) {
r.setBar(desc.bar); // Hook to your code here!
}
public Response delete() {
r.close(); // Hook to your code here!
return Response.noContent().build(); // Return a simple HTTP 204
}
};
}
}
Now, plumbing it together at the Spring level with a WEB-INF/beans.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">
<!-- Instantiate and connect the service framework -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-jaxrs-binding.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<jaxrs:server id="customerService" address="/">
<jaxrs:serviceBeans>
<ref bean="fooBean" />
</jaxrs:serviceBeans>
</jaxrs:server>
<!-- Instantiate your implementation class -->
<bean id="fooBean" class="your.package.FooImpl" />
</beans>
Now, to hook it all up as a webapp, a web.xml:
<web-app>
<!-- Magic to make Spring work and build the rest for us -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/beans.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- Make CXF implement the servlet for us -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<display-name>CXF Servlet</display-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- You *must* use this servlet mapping or Bad Things Happen. -->
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Now build a WAR including all the libs listed on the CXF site, putting the bits in the right places (you don't need Maven for this, but in the end it makes it easier) and deploy. That ought to work (i.e., you've now got enough to be dangerous!)
Related
I am attempting to recreate the most excellent vogella tutorial for create REST with java, JAX-RS and Jersey.
I'm using eclipse Kepler with Java-EE perspective, tomcat 7.0.
I have create the Todo class, the TodoResource class with the appropriate annotations and deployed on tomcat 7. I have imported the jaxrs-ri libs into the WEB-INF/lib folder as instructed.
Todo class:
package com.vogella.jersey.jaxb.model;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Todo {
private String summary;
private String description;
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
TodoResource with annotations:
package com.vogella.jersey.jaxb.model;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/todo")
public class TodoResource {
// This method is called if XMLis request
#GET
#Produces({ MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
public Todo getXML() {
Todo todo = new Todo();
todo.setSummary("This is my first todo");
todo.setDescription("This is my first todo");
return todo;
}
// This can be used to test the integration with the browser
#GET
#Produces({ MediaType.TEXT_XML })
public Todo getHTML() {
Todo todo = new Todo();
todo.setSummary("This is my first Todo");
todo.setDescription("This is my first Todo");
return todo;
}
}
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>com.vogella.jersey.first</display-name>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.vogella.jersey.jaxb</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
</web-app>
I have also created the client as instructed.
Test.java:
package com.vogella.jersey.first.client;
import java.net.URI;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientResponse;
import org.glassfish.jersey.message.internal.MediaTypes;
public class Test {
public static void main(String[] args) {
ClientConfig config = new ClientConfig();
Client client = ClientBuilder.newClient(config);
WebTarget target = client.target(getBaseURI());
System.out.println(target.path("rest").path("todo").request()
.accept(MediaType.APPLICATION_XML ).get(Response.class)
.toString());
System.out.println(target.path("rest").path("todo").request()
.accept(MediaType.APPLICATION_JSON ).get(Response.class)
.toString());
}
private static URI getBaseURI() {
return UriBuilder.fromUri("http://localhost:8080/com.vogella.jersey.jaxb").build();
}
}
Everything works perfectly for the MediaType.APPLICATION_XML - the server returns:
InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:8080/com.vogella.jersey.jaxb/rest/todo, status=200, reason=OK}}
However, for the MediaType APPLICATION_JSON - which is what I actually need, I get an error:
InboundJaxrsResponse{ClientResponse{method=GET, uri=http://localhost:8080/com.vogella.jersey.jaxb/rest/todo, status=500, reason=Internal Server Error}}
Tomcat clearly shows me the problem - it seems to me it doesn't know how to return a JSON response -
Nov 02, 2014 11:59:19 AM org.glassfish.jersey.message.internal.WriterInterceptorExecutor$TerminalWriterInterceptor aroundWriteTo
SEVERE: MessageBodyWriter not found for media type=application/json, type=class com.vogella.jersey.jaxb.model.Todo, genericType=class com.vogella.jersey.jaxb.model.Todo.
My understanding is that the jaxrs-ri 2.13 bundle includes everything required including dependencies to let me do this - and that I don't need to add any kind of JSON provider. I have done so anyway, I have tried adding gson for example, I have downloaded the moxy jars and attempting to add them to my WEB-INF/lib folder and deploy - all to no avail. I don't know if I'm completely out in the weeds, or if I'm missing something simple?
My understanding is that the jaxrs-ri 2.13 bundle includes everything required including dependencies to let me do this - and that I don't need to add any kind of JSON provider.
That's actually incorrect. As stated at the Jersey User Guide 8.1. JSON
Jersey JSON support comes as a set of extension modules where each of these modules contains an implementation of a Feature that needs to be registered into your Configurable instance (client/server). There are multiple frameworks that provide support for JSON processing and/or JSON-to-Java binding. The modules listed below provide support for JSON representations by integrating the individual JSON frameworks into Jersey. At present, Jersey integrates with the following modules to provide JSON support:
MOXy - JSON binding support via MOXy is a default and preferred way of supporting JSON binding in your Jersey applications since Jersey 2.0. When JSON MOXy module is on the class-path, Jersey will automatically discover the module and seamlessly enable JSON binding support via MOXy in your applications. (See Section 4.3, “Auto-Discoverable Features”.)
Among a few others
So the main Jersey download doesn't come with these extra modules. We need to obtain them separately. That being said, the easiest way to get the required jersey-media-moxy is through Maven.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.13</version>
</dependency>
If you're not using Maven (which looking through the tutorial, it doesn't), you're going to have to do some searching for the dependencies. The jersey-media-moxy artifact has 16 dependencies, but Fortunately, most are contained within the Jersey distribution. So after filtering out what was already included in the Jersey distro, these are the remaining jars you will have to find on your own (I just created a User Library to test out)
Adding these dependencies will get the example up and running. Tested and works as expected after adding these.
Now you have Eclipse, which I assume came with the Maven (m2e) plugin. So maybe the easiest way to get these dependencies is to create a new Maven project, and add the dependency shown above. After you build the project, maven should download all the extra dependencies into your local Maven Repo. Just grab them from there for your main project.
Other Resources/Notes
Jersey User Guide
I would download the Jersey Example package, which is more up to date then the tutorial you are using.
If you don't know Maven, I would strongly suggest learning at least the basic of dependency management, and let the build framework grab all the dependencies for you. Also all the examples in the examples package uses Maven, so it would help to know the basics.
If your are using Jersey-2
Web.xml Configuration
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servletclass>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.oracle.restful</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
List of Libraries required
org.eclipse.persistence.moxy-2.6.3.jar
org.eclipse.persistence.core-2.6.3.jar
org.eclipse.persistence.asm-2.6.3.jar
org.eclipse.persistence.antlr-2.6.3.jar
jersey-media-moxy-2.23.1.jar
jersey-entity-filtering-2.23.1.jar
Run project it will work. Also check your JAXB classed because it will internally use xml annotation to convert pojo object to JAXB
Have you written any custom MessageBodyWriter for your marshalling from Java to JSON. If yes then you need to have the #Produces annotation with 'application/json' in the provider implementation. For more details refer http://h2labz.blogspot.in/2014/12/marshalling-java-to-json-in-jax-rs.html
I have set up an App Engine Restlet Project (v 2.2.2) which returns a html or json response (web or android client) and different data from a db for different users. I have implemented HTTP basic authentication. It all works quite well.
my basic setup atm (I have simplified it ofc):
MyApplication.java
public class MyApplication extends Application {
private ChallengeAuthenticator authenticatior;
private ChallengeAuthenticator createAuthenticator() {...}
public boolean authenticate(Request request, Response response) {...}
#Override
public Restlet createInboundRoot() {
this.authenticatior = createAuthenticator();
Router router = new Router(getContext());
router.attachDefault(MyRestlet.class);
authenticatior.setNext(router);
return authenticatior;
}
MyRestlet.java
public class MyRestlet extends ServerResource {
#Get("json")
public Representation getJSON() {
MyApplication app = (MyApplication) getApplication();
if (!app.authenticate(getRequest(), getResponse())) {
// Not authenticated
return null;
}
else {
return data;
}
#Get("html")
public String getHTML() {...}
}
web.xml
<?xml ...>
<display-name>MyName</display-name>
<context-param>
<param-name>org.restlet.application</param-name>
<param-value>x.MyApplication</param-value>
</context-param>
<servlet>
<servlet-name>MyRestlet</servlet-name>
<servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MyRestlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Now I want to add encryption and created keys/certificates. My guide was this tutorial. I wanted to try to add a simple component first, stay with HTTP and change the port to 8183 as done in this tutorial. I have now played around quite a bit and cannot seem to get my component to work. So my question is: Where would I put this main-Method (the following code is taken from the tutorial)? Into which class should I insert it or should I create a seperate server-class and what exactly would the required changes to the web.xml look like (I did not find much concerning this and I suspect that this is the central problem)? Any help is appreciated!
public static void main(String[] args) throws Exception {
// Create a new Restlet component and add a HTTP server connector to it
Component component = new Component();
component.getServers().add(Protocol.HTTP, 8182);
// Then attach it to the local host
component.getDefaultHost().attach("/trace", Part05.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
Your question is slightly confusing, probably because of the path you have taken.
Your original plan creates a RESTlet web application, complete with web.xml to run inside a container, such as GAE, Jetty or Tomcat.
What you're proposing creates a component and starts a stand alone server (it starts an internal instance of Jetty). This won't work on Google App Engine.
You should continue with the web.xml approach and configure GAE to serve over https. See https://cloud.google.com/appengine/kb/general#https and https://cloud.google.com/appengine/docs/java/config/webxml#Secure_URLs for configuration instructions.
Also, another tip: return 403 status when something attempts to access a resource without authorisation.
So I was trying to convert a JavaSE RESTLET app to a JavaEE app. What I understood from the "Restlet in Action" book, Pg 72, is that we dont need to attach a server to the component as Servlet engine handles the incoming HTTP and HTTPS requests.
The tutorial also points to the component file an an INIT-PARAM or param-name in your web.xml. However for me, none of above 2 changes are working.
If I point to the application class as an INIT-PARAM and not use a HTTP connector as suggested in the book, i am able to access the APIs but not able to make any calls from the client class as I get the below error -
WARNING: The protocol used by this request is not declared in the list of client connectors. (HTTP/1.1). In case you are using an instance of the Component class, check its "clients" property.
Not Found (404) - The server has not found anything matching the request URI
Hope these info help you in some way
EDIT
I found the solution to the above problem -
I had to add the below piece of code
<init-param>
<param-name>org.restlet.clients</param-name>
<param-value>HTTP HTTPS FILE</param-value>
</init-param>
Also for your problem, you need to configure the Component via an XML. Below URLs will give more info -
http://restlet.com/learn/javadocs/2.1/jee/ext/org/restlet/ext/servlet/ServerServlet.html
http://restlet.com/learn/javadocs/2.1/jee/api/org/restlet/Component.html?is-external=true
What is needed:
There is simple web application running on Tomcat at address http://localhost:8080/.
Handler for following URL should be added:
GET http://localhost:8080/request/report/custom_report?from=2013-10-12&to=2014-10-12&download=true
which will simply write to the HttpServletResponse some data i.e. no views are involved.
What was done:
As per official Spring MVC documentation following mapping of DispatcherServlet was added to web.xml
<servlet>
<servlet-name>springDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springDispatcher</servlet-name>
<url-pattern>/request/*</url-pattern>
<!-- PLEASE NOTE that mapping to /* is not an option -->
</servlet-mapping>
Now, because latest spring-webmvc-4.0.5.RELEASE is used I would like to add above mentioned handler with the minimum XML or Java configuration possible, so I create controller class:
package org.yura.servlet.spring;
#Controller
public class SpringRequestController {
#RequestMapping(value = "/report/custom_report",
method = GET,
produces = "application/pdf")
public void getCustomReport(
#RequestParam("from") #DateTimeFormat(pattern = "yyyy-MM-dd") final Date from,
#RequestParam("to") #DateTimeFormat(pattern = "yyyy-MM-dd") final Date to,
#RequestParam("download") final boolean download,
final HttpServletResponse response) throws IOException {
takeParamsAndWriteReportAsPdfToServletResponse(from, to, download, response.getOutputStream());
}
Then, in order for this Controller to be "picked up" by Spring I put springDispatcher-servlet.xml right next to web.xml in WEB-INF folder with following configuration (please advise if it can be simplified even more):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="org.yura.servlet.spring" />
</beans>
The Problem
With this configuration, after starting Tomcat and navigating to above mentioned URL I get Error 404.
Question 1: Please advise what is wrong with handler URLs - should I specify them as relative or what? (because as per logs, DispatcherServlet is created normally)
Question 2: Is it possible to move configuration from springDispatcher-servlet.xml to my Controller class in order not to scatter request-handling logic across multiple files.
Thanks in advance...
You haven't enabled your MVC stack. Add
<mvc:annotation-driven />
to your springDispatcher-servlet.xml (along with the appropriate namespaces).
The configuration in springDispatcher-servlet.xml is not simply request handling configuration. It can contain any bean declaration. If anything, you can move it to a Java configuration, but it should not be part of your #Controller source code.
Background: I'm relatively new to Java/Spring and inherited a project built on them. We're moving to AWS Elastic Beanstalk which changed the location of the main page for JSON requests from:
www.mywebsite.com/myApp/myAppJsonService
to:
www.mywebsite.com/myAppJsonService
That worked fine- all the functions that come out the JSON requests (most of them) are working perfectly. I have another page that takes a teacher's uploaded quiz via HTML form submit and parses the data. The form used to point to:
www.mywebsite.com/myApp/controllers/importQuiz
so I changed it to:
www.mywebsite.com/controllers/importQuiz
The web.xml file has:
<servlet>
<servlet-name>SpringDispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:context/Controllers.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>SpringDispatcher</servlet-name>
<url-pattern>/controllers/*</url-pattern>
</servlet-mapping>
And the corresponding Controllers.xml code:
<bean id="importExamController" class="com.myapp.controllers.ImportExamController">
<property name="commandClass" value="com.myapp.objects.spring.FileUploadBean"/>
<property name="myappManager" ref="myappManager"/>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/importExam">importExamController</prop>
<prop key="/heartbeat">heartBeatController</prop>
</props>
</property>
</bean>
The way I read it, regardless of the preceding "myapp" in the URL, it should find "/controllers/" in the URL, look to the Controllers.xml file and find the "/importExam" and direct it to the "importExamController". That's not happening. Clearly, there is a fault in my logic, and I can't seem to find it. Any help would be very much appreciated.
EDIT:
Doing some digging through the logs, I found:
INFO: WSSERVLET14: JAX-WS servlet initializing
Aug 27, 2011 7:21:06 PM com.sun.xml.ws.transport.http.servlet.WSServletDelegate doGet
SEVERE: caught throwable
ClientAbortException: java.net.SocketException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.realWriteBytes(OutputBuffer.java:373)
at org.apache.tomcat.util.buf.ByteChunk.append(ByteChunk.java:327)
at org.apache.catalina.connector.OutputBuffer.writeBytes(OutputBuffer.java:396)
at org.apache.catalina.connector.OutputBuffer.write(OutputBuffer.java:385)
and it goes on for a while. To me it looks like that is confirming the idea that the data is trying to be sent to something that is incorrectly mapped. Let me know if this might mean something else or if it's just irrelevant.
First off, why in the world would you want controllers in your URL? Secondly, you have the right idea of how it should work, and you're probably correct about something not being configured correctly.
You should really read up on the enhanced MVC functionality in Spring 3.0+. With annotations and the mvc namespace, your code would look like (e.g.):
#Controller
#RequestMapping("importExam")
public class ExamController {
private final examService;
#Autowired
public ExamController(ExamService examService) {
this.examService = examService;
}
#RequestMapping(method=RequestMethod.GET)
public String getExams(ModelMap model) {
model.addAttribute("exams", examService.getExams());
return "exams";
}
}
And your controller is just:
<mvc:annotation-config/>
to load the controller and bind the request mappings to urls. This allows for wildcards too. The above controller would wire all URL request for /importExam to this controller, and process the default GET method at the base context. You could add nested methods with additional request mappings which would reside beneath the /importExam context.
I want a Servlet to handle requests to files depending on prefix and extension, e.g.
prefix_*.xml
Since mapping on beginning AND end of request path is not possible, I have mapped all *.xml requests to my Servlet.
The question now is: how can I drop out of my servlet for XML files not starting with "prefix_", so that the request is handled like a "normal" request to an xml file?
This is probably quite simple but I do not seem to be able to find this out... :-/
Thanks a lot in advance
another solution (maybe fits for you) is if you are using/plan to use an Apache in front of that web container instance you could use the rewrite module of apache. Rewriting the url to something more easy to handle for the Webapp container.
Hope this helps.
David.
I would strongly suggest using a proper MVC framework for this. As you've discovered, the flexibility of the standard servlet API is very limited when it comes to request dispatching.
Ideally, you would be able to use your existing servlet code in combination with an MVC framework, with the framework doing the diapcthing based on path pattern, and your servlets doing the business logic. Luckily, Spring MVC allows you to do just that, using the ServletForwardingController. It'd be a very lightweight spring config.
So you'd have something like this in your web.xml:
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>foo.MyServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
</servlet>
<url-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>*</url-pattern>
</url-mapping>
You would then have a WEB-INF/spring-servlet.xml file like this:
<beans>
<bean name="/prefix*.xml" class="org.springframework.web.servlet.mvc.ServletForwardingController">
<property name="servletName" value="myServlet"/>
</bean>
</beans>
And that would be pretty much it. All requests for /prefix*.xml would go to myServlet, and all others would fall through to the container.
Not shure, but once you catch all *.xml requests you can inspect the request again in your code via HttpServletRequest.getRequestURI()
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String uri =req.getRequestURI();
int i = uri.lastIndexOf('/');
int j = uri.lastIndexOf('.', i);
if (uri.substring(i+1, j).startsWith("prefix_")) {
// your code
}
}
(code not tested, only an idea ...)