Jersey with embedded Jetty + PostReplaceFilter - java

I am using Jersey with an embedded Jetty according to the documentation http://wiki.eclipse.org/Jetty/Tutorial/Embedding_Jetty. This works fine so far. What I'd like to add now is usage of the PostReplaceFilter in this configuration.
Normally this is done in the web.xml like this
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.PostReplaceFilter</param-value>
</init-param>
But using the embedded Jetty I have no web.xml. I tried setting the filter programmatically like this
ServletContextHandler sch = new ServletContextHandler(server, "myapp");
sch.setInitParameter("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.PostReplaceFilter");
But this does not show any effect. Can anyone shed light on how to install a PostReplaceFilter using Java code?
Thanks in advance
I looks like I missed to mention one important fact, which is that I am using Google Guice. Therefore there is no ServletHolder where I could set initialization parameters. Instead I could finally find the answer in the Guice documentation at http://code.google.com/p/google-guice/wiki/ServletRegexKeyMapping in the section on "Initialization Parameters". So for the PostReplaceFilter this would look like this:
Map<String, String> params = new HashMap<String, String>();
params.put("com.sun.jersey.spi.container.ContainerRequestFilters", "com.sun.jersey.api.container.filter.PostReplaceFilter");
serve("/*").with(GuiceContainer.class, params);

You should set it using the setInitParameter() on the ServletHolder instance that you use to register the Jersey servlet.

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.

Initializing Jetty+Jersey

I'm trying to initialize Jetty with the following code:
URI baseUri = UriBuilder.fromUri("http://localhost/").port(config.getPort()).build();
ResourceConfig resConfig = new ResourceConfig(GetFutureTimetableCommand.class);
Server server = JettyHttpContainerFactory.createServer(baseUri, resConfig);
WebAppContext context = new WebAppContext();
context.setDescriptor("WebContent/WEB-INF/web.xml");
context.setResourceBase("WebContent");
context.setContextPath("rest/*");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
My Resource looks like this:
#Path("/timetable")
public class GetFutureTimetableCommand extends CMSCommand {
#GET
#Produces(MediaType.APPLICATION_JSON)
public CMSBean execute(#PathParam("param") String params) {
System.out.println("GOOD");
return new FutureTimetable(8202L, DateTime.now().plusDays(2));
}
}
And from the browser:
http://localhost:8080/rest/timetable
But nothing really happens, what am I doing wrong??
I have found that enabling MBeans with monitoring statistics invaluable when trying to determine why a resource isn't executing.
Add the below to your Jersey Servlet definition in your web.xml and connect JVisualVM or JConsole to see lots of data on deployed resources.
<init-param>
<param-name>jersey.config.server.monitoring.statistics.mbeans.enabled</param-name>
<param-value>true</param-value>
</init-param>
I appreciate this isn't an answer to your problem, but hopefully should help you find it.
Will
It seems only the root context path is taken into account when jersey is used together with jetty as per Jersey documentation (others are just ignored):
https://jersey.java.net/documentation/latest/deployment.html
You probably need to change the context path with:
context.setContextPath("/");

Url pattern to exclude javax.faces.resource from being invoked by servlet filter

I have created a servlet filter to handle session timeout and authentication.
#WebFilter(urlPatterns={"/acc/*"})
public class ResourceAuthorizationFilter implements Filter { ... }
The pages that I want to filter have a pattern like this: /acc/login-flow, /acc/profiles-flow. The filter gets called also for resources(css, js and images). How can I configure the urlPatterns to exclude from filtering these resources?
EDIT1
Here are some urls that are filtered:
http://localhost:8081/acme-0.0.1/acc/login-flow
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/theme.css
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/jquery/jquery.js
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/primefaces.js
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/ajax.gif
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/login.png
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/header.png
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/images/ui-bg_flat_75_ffffff_40x100.png
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/images/default.png
http://localhost:8081/acme-0.0.1/acc/javax.faces.resource/images/ui-icons_888888_256x240.png
I have some custom css/js files under webapp/resources folder, but these ones are not from there.
The acc part comes from:
<servlet-mapping>
<servlet-name>Spring MVC Servlet</servlet-name>
<url-pattern>/acc/*</url-pattern>
</servlet-mapping>
EDIT2
These code samples come from a project that is implemented with JSF 2.0, PrimeFaces 3.4.1, Spring 3.0.5.RELEASE, Spring Security 3.0.3.RELEASE and Spring Web Flow 2.3.0.RELEASE.
Just move resources to a different folder outside /acc. They're by default supposed to be in /resources folder anyway so that you can use <h:outputScript>, <h:outputStylesheet> and <h:graphicImage> the right way.
If you can't fix that for some reason, then you'd really need to check the request URI in the doFilter() implementation. There's namely no way to exclude sub-patterns in an URL pattern.
String path = request.getRequestURI().substring(request.getContextPath().length());
if (path.startsWith("/acc" + ResourceHandler.RESOURCE_IDENTIFIER)) {
chain.doFilter(request, response);
} else {
// ...
}
Update: as per your question update, you're using Spring MVC for some unclear reason. It's also processing all JSF resource requests. You should tell it to not do that. I can't tell from top of head how to do that, but it's at least something with <mvc:resources>.
If you are already using Spring Security in your project. It is easy to register your custom session management filter in the security context and then you can easily exclude the pattern adding a new intercept-url element like this:
<intercept-url pattern="/javax.faces.resource/**" filters="none"/>
Refer to namespace config documentation.
If set to "none" then the path is removed from having any filters applied.
See also:
Example of a custom session management filter : JSF 2, Spring Security 3.x and Richfaces 4 redirect to login page on session time out for ajax requests
spring security css styles don't work

Message level Jax-WS service

I'm trying to create a WebService stub. I like to react to all of the request in one single place. I have a sample value generator, which handles the type of the request and creates a sample response, so I don't need the code-generation things with a lots of classes. Only a really simple one.
I have found http://jax-ws.java.net/nonav/2.2.1/docs/provider.html WebServiceProvider which is exactly for getting raw SOAP messages, and create a response in a single place.
The main problem is I'm new to this magical EE world :) and I simply can not start WebServiceProvider sample anyway.
I have Spring, SpringSource ToolSuit, Axis installed/configured, all of the other things are working.
Thank you all for your help, and please excuse me if the question is too simple for you. Maybe I just did not find/read something.
M.
Finally I have found the solution (thanks for the help from my workmates).
If you are using JAX-WS, there is a simple solution.
You need a sun-jaxws.xml in your WEB-INF folder containing the following:
<?xml version="1.0" encoding="UTF-8"?>
<endpoints xmlns="http://java.sun.com/xml/ns/jax-ws/ri/runtime" version="2.0">
<endpoint
name="RawWS"
implementation="com.stg.pack.MyServiceProvider"
url-pattern="/HotelServices200631"/>
</endpoints>
And you need a com.stg.pack.MyServiceProvider class which looks like:
package com.stg.pack;
#ServiceMode(value = Service.Mode.MESSAGE)
#WebServiceProvider(portName = "ThePortNameOfWebService",
serviceName = "TheNameOfWebService",
targetNamespace = "http://www.example.com/target/namespace/uri")
public class MyServiceProvider implements Provider<SOAPMessage> {
#Override
public SOAPMessage invoke(SOAPMessage request) {
SOAPMessage result = null;
// create response SOAPMessage
return result;
}
}
And before I forget, you need to define some things in web.xml:
<listener>
<listener-class>
com.sun.xml.ws.transport.http.servlet.WSServletContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>RawWS</servlet-name>
<servlet-class>
com.sun.xml.ws.transport.http.servlet.WSServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RawWS</servlet-name>
<url-pattern>/TheNameOfWebService</url-pattern>
</servlet-mapping>
If you use it like this, all of the request are handled by the invoke method.
you basically must deploy your provider to some sort of Container. developing in J/EE basically mandates that you compile some sort of EAR or WAR or JAR and tell an app server to deploy it (be that app server a JBOSS, glassfish, Weblogic, Websphere, Tomcat, etc).
Have you tried doing this?
it also may be possible to test your provider using the javax.xml.ws.Endpoint class, although I have to admit I've never chosen to per-sue this in favor of deploying to an app server.

Filters in tomcat

I am facing a task to add a dependent jar application to an existing one. The existing one does not use to much of locale benefits and so on, but my new one should.
So like I have now: localhost:8080/old-app
I want to have also: localhost:8080/[en|fr|...]/new-module
Could anyone point me the direction, because even if I think I get the idea of filters, filter-mapping, I cannot manage to solve it.
I would like to keep the old one and also have access to the new one.
Deploy new-module as ROOT.war (or set path in /META-INF/context.xml to /). Use Tuckey's URLRewriteFilter to rewrite specific URL's and transform the language part to a request parameter so that it's available by request.getParameter(). It's much similar to Apache HTTPD's mod_rewrite.
An alternative to URLRewriteFilter is to homegrow a custom filter which does like the following in doFilter() method.
String uri = request.getRequestURI();
if (uri.matches("^/\\w{2}(/.*)?$")) {
request.setAttribute("language", uri.substring(1, 3));
request.getRequestDispatcher(uri.substring(3)).forward(request, response);
} else {
chain.doFilter(request, response);
}
Map this on an url-pattern of /*. The language will be available by request.getAttribute("language") on the forwarded resource.
If you dont want the applications name as context root e.g. localhost:8080/appname but under / directly you have to put it into the tomcat/webapps/ROOT folder. To get more sophisticated URL mappings working have a look at http://ocpsoft.com/prettyfaces/

Categories