I have a service implemented with Dropwizard and I need to dump incorrect requests somewhere.
I saw that there is a possibility to customise the error message by registering ExceptionMapper<JerseyViolationException>. But I need to have the complete request (headers, body) and not only ConstraintViolations.
You can inject ContainerRequest into the ExceptionMapper. You need to inject it as a javax.inject.Provider though, so that you can lazily retrieve it. Otherwise you will run into scoping problems.
#Provider
public class Mapper implements ExceptionMapper<ConstraintViolationException> {
#Inject
private javax.inject.Provider<ContainerRequest> requestProvider;
#Override
public Response toResponse(ConstraintViolationException ex) {
ContainerRequest request = requestProvider.get();
}
}
(This also works with constructor argument injection instead of field injection.)
In the ContainerRequest, you can get headers with getHeaderString() or getHeaders(). If you want to get the body, you need to do a little hack because the entity stream is already read by Jersey by the time the mapper is reached. So we need to implement a ContainerRequestFilter to buffer the entity.
public class EntityBufferingFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext containerRequestContext) throws IOException {
ContainerRequest request = (ContainerRequest) containerRequestContext;
request.bufferEntity();
}
}
You might not want this filter to be called for all requests (for performance reasons), so you might want to use a DynamicFeature to register the filter just on methods that use bean validation (or use Name Binding).
Once you have this filter registered, you can read the body using ContainerRequest#readEntity(Class). You use this method just like you would on the client side with Response#readEntity(). So for the class, if you want to keep it generic, you can use String.class or InputStream.class and convert the InputStream to a String.
ContainerRequest request = requestProvider.get();
String body = request.readEntity(String.class);
What is the Wicket way of serving user-uploaded assets from AWS S3?
Requirements:
No direct requests from browser to S3; all traffic is proxied through our servers;
Allow assets to be cached by the browser with cache busting (either via checksums or a version field in the database);
Asset are served to authorized users only.
I can think of the following solutions:
A single SharedResource for all resources that parses the URL and streams the assets:
// resource definition:
mountResources("/assets/${path}", new ResourceReference("assets") {
public IResource getResource() {
return new AbstractResource() {
public ResourceResponse newResourceResponse(RequestAttribute attributes) {
String path = attributes.getParameters().get("path").toString()
// request S3 and stream the content
// handle caching / busting by hand
}
}
}
})
// Usage:
page.add(new Image("image", new SharedResourceReference("assets"), new PageParameters().add("path", "image.jpg"))
Create a new ResourceReference for each asset and pass it directly to image. Plug into Wicket's caches by letting the Resource implement IStaticCacheableResource:
class S3ResourceReference extends ResourceReference {
private String path;
public S3ResourceReference(String path) { ... }
public IResource getResource() {
return new S3Resource(path);
}
}
class S3Resource extends AbstractResource implements IStaticCacheableResource {
public S3ResourceStream getResourceStream() {
S3Object object = getObject(path);
return new S3ResourceStream(object);
}
public ResourceResponse newResourceResponse(Attributes attributes) {
S3ResourceStream stream = getResourceStream();
// populate response
}
}
class S3ResourceStream extends AbstractResourceStream {
S3ResourceStream(S3Object object) {
// ...
}
public InputStream getInputStream() { return object.objectContent }
// override metadata methods
}
// Usage:
page.add(new Image("image"), new S3ResourceReference("image.jpg"));
Which of these approaches look more idiomatic?
Are there any pitfalls with usage of IStaticCacheableResource in the second snippet?
Here are the differences in those two approaches:
Page instance locking
In 1) the requests for the resources are made to an application scoped resource
In 2) the request is to a page scoped resource
In the second case Wicket will lock the access to the page instance during the serving of the resource. For that reason I prefer using the application scoped resource.
IStaticCacheableResource
If the resource implements this interface then Wicket will mangle the produced url to the resource and will add something like -123456789 in its file name. This hash is the resource modification time in DEVELOPMENT mode and its MD5 checksum in PRODUCTION mode. This helps for caching.
I hope you realize that you can use a mix of 1) and 2) - an application scoped resource reference + IStaticCacheableResource.
One more thing: I usually use new MyResourceReference() instead of new SharedResourceReference("the-name").
I am trying to access following sling servlet using http://localhost:4502/sling/test-services/planet.html
But, it is giving 404 error, not sure what I am doing wrong here.
#Component
#Service(value=javax.servlet.Servlet.class)
#Properties({
#Property(name="service.description", value="HTML renderer for Planet resources"),
#Property(name="service.vendor", value="The Apache Software Foundation"),
#Property(name="sling.servlet.resourceTypes", value="sling/test-services/planet"),
#Property(name="sling.servlet.extensions", value="html"),
#Property(name="sling.servlet.methods", value="GET")
})
#SuppressWarnings("serial")
public class PlanetResourceRenderingServlet extends SlingSafeMethodsServlet {
#Override
protected void doGet(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
final ValueMap properties = request.getResource().adaptTo(ValueMap.class);
// TODO should escape output - good enough for our tests
final PrintWriter pw = response.getWriter();
pw.println(String.format("<html><head><title>Planet at %s</title></head><body>", request.getResource().getPath()));
pw.println(String.format("<p>Name: %s</p>", properties.get("name")));
pw.println(String.format("<p>Distance: %s</p>", properties.get("distance")));
pw.println("</body></html>");
pw.flush();
}
}
Is it possible, I could access the servlet service without ".html" extension, if I remove extension property?
I appreciate any help.
Thank you!
When you want to access a servlet through an URL you need to set the sling.servlet.paths instead of the sling.servlet.resourceTypes. A similar issue has been answered here.
If you are setting the sling.servlet.resourceTypes property, then you need to access a resource whose sling:resourceType is sling/test-services/planet.
Your annotations should be
#Component
#Service(value=javax.servlet.Servlet.class)
#Properties({
#Property(name="service.description", value="HTML renderer for Planet resources"),
#Property(name="service.vendor", value="The Apache Software Foundation"),
#Property(name="sling.servlet.paths", value="/sling/test-services/planet"),
#Property(name="sling.servlet.extensions", value="html"),
#Property(name="sling.servlet.methods", value="GET")
})
Or this can be further simplified using the #SlingServlet annotation as shown below
#SlingServlet(paths="/sling/test-services/planet", methods="GET", extensions="html")
Make sure that you allow the following path is allowed in Apache Sling Servlet/Script Resolver and Error Handler configuration available in OSGi console.
Im trying to use CDI extensions to discover JAX-RS resources at runtime and automatically publish them under different base URIs in a Java SE environment. Applications should not need to extend javax.ws.rs.core.Application themselves if possible.
I have read RestEasy documentation and javadoc but failed to find any obvious way to modify the #ApplicationPath at runtime.
One idea that im exploring is to try generate javax.ws.rs.core.Application and set the #ApplicationPath base URI programmatically, maybe by using an AnnotatedType CDI extension, and publish that as a * org.jboss.resteasy.spi.ResteasyDeployment`.
Are there other/better ways to do this?
EDIT:
Trying CDI extension event ProcessAnnotatedType to change #javax.ws.rs.Path of JAX-RS resources.
<X> void process(#Observes ProcessAnnotatedType<X> pat) {
if (!pat.getAnnotatedType().isAnnotationPresent(javax.ws.rs.Path.class)) {
return;
}
final AnnotatedType<X> org = pat.getAnnotatedType();
AnnotatedType<X> wrapped = new AnnotatedType<X>() {
#Override
public <T extends Annotation> T getAnnotation(final Class<T> annotation) {
if (javax.ws.rs.Path.class.equals(annotation)) {
class PathLiteral extends AnnotationLiteral<javax.ws.rs.Path> implements javax.ws.rs.Path {
#Override
public String value() {
return "change_me/" + (javax.ws.rs.Path) org.getAnnotation(annotation);
}
}
return (T) new PathLiteral();
} else {
return org.getAnnotation(annotation);
}
}
pat.setAnnotatedType(wrapped);
}
... then after bootstrap, constructing the bean using javax.enterprise.inject.spi.BeanManager was expecting the following code to print "change_me/...."
Set<Bean<?>> beans = beanManager.getBeans(jaxrsClass);
for (Bean<?> bean : beans) {
CreationalContext cc = bm.createCreationalContext(bean);
Object jaxrs = bean.create(cc);
Path p = jaxrs.getClass().getAnnotation(Path.class);
System.out.println(p.value());
}
... but this does not work. javax.ws.rs.Path is unchanged for JAX-RS resource 'jaxrsClass'.
What is wrong?
I doubt this can be done in a reliable way. It probably all comes down to which happens first: the CDI bootstrap or JAX-RS, of course in the future or in other application servers it could all be done in parallel.
It's certainly a cool idea though. What have they said on the RestEasy forums?
We are already using such an approach.
We are using the feature to use Subresource locators and take the power of guice.
At the startup we are scanning the classpath for all resources annotated with #Path. After that we are extracting the path and binding the resources with the help of Names/#Named. So the resources can later be injected with the help of the name.
bind(..).annotatedWith(Names.named("path")).to(..)
The next step is that you need a resource with a subresource locator.
#Path("{name}")
public Object find(#PathParam("name") name){
return injector.getInstance(..);
}
You could use this approach to bind them at runtime and also to change the original annotated path.
I'm having this problem with GWT when it's behind a reverse proxy. The backend app is deployed within a context - let's call it /context.
The GWT app works fine when I hit it directly:
http://host:8080/context/
I can configure a reverse proxy in front it it. Here's my nginx example:
upstream backend {
server 127.0.0.1:8080;
}
...
location / {
proxy_pass http://backend/context/;
}
But, when I run through the reverse proxy, GWT gets confused, saying:
2009-10-04 14:05:41.140:/:WARN: Login: ERROR: The serialization policy file '/C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc' was not found; did you forget to include it in this deployment?
2009-10-04 14:05:41.140:/:WARN: Login: WARNING: Failed to get the SerializationPolicy 'C7F5ECA5E3C10B453290DE47D3BE0F0E' for module 'https://hostname:444/'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.
2009-10-04 14:05:41.292:/:WARN: StoryService: ERROR: The serialization policy file '/0445C2D48AEF2FB8CB70C4D4A7849D88.gwt.rpc' was not found; did you forget to include it in this deployment?
2009-10-04 14:05:41.292:/:WARN: StoryService: WARNING: Failed to get the SerializationPolicy '0445C2D48AEF2FB8CB70C4D4A7849D88' for module 'https://hostname:444/'; a legacy, 1.3.3 compatible, serialization policy will be used. You may experience SerializationExceptions as a result.
In other words, GWT isn't getting the word that it needs to prepend /context/ hen look for C7F5ECA5E3C10B453290DE47D3BE0F0E.gwt.rpc, but only when the request comes throught proxy. A workaround is to add the context to the url for the web site:
location /context/ {
proxy_pass http://backend/context/;
}
but that means the context is now part of the url that the user sees, and that's ugly.
Anybody know how to make GWT happy in this case?
Software versions:
GWT - 1.7.0 (same problem with 1.7.1)
Jetty - 6.1.21 (but the same problem existed under tomcat)
nginx - 0.7.62 (same problem under apache 2.x)
I've looked at the traffic between the proxy and the backend using DonsProxy, but there's nothing noteworthy there.
I have the same problem, and I opened a bug report:
http://code.google.com/p/google-web-toolkit/issues/detail?id=4817
The problem is that it was marked "As Design", so I don't think it will be fixed.
I found this solution for me. I extended the class RemoteServiceServlet and I forced GWT to load serialization policy file starting from ContextName instead of URL.
Then I extended my service my class instead of RemoteServiceServlet class.
In this way the application will be unlinked from the url from where it will be called.
Here there is my custom class:
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.ParseException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.gwt.user.server.rpc.SerializationPolicy;
import com.google.gwt.user.server.rpc.SerializationPolicyLoader;
public class MyRemoteServiceServlet extends RemoteServiceServlet
{
#Override
protected SerializationPolicy doGetSerializationPolicy(HttpServletRequest request, String moduleBaseURL, String strongName)
{
return MyRemoteServiceServlet.loadSerializationPolicy(this, request, moduleBaseURL, strongName);
}
/**
* Used by HybridServiceServlet.
*/
static SerializationPolicy loadSerializationPolicy(HttpServlet servlet,
HttpServletRequest request, String moduleBaseURL, String strongName) {
// The serialization policy path depends only by contraxt path
String contextPath = request.getContextPath();
SerializationPolicy serializationPolicy = null;
String contextRelativePath = contextPath + "/";
String serializationPolicyFilePath = SerializationPolicyLoader.getSerializationPolicyFileName(contextRelativePath
+ strongName);
// Open the RPC resource file and read its contents.
InputStream is = servlet.getServletContext().getResourceAsStream(
serializationPolicyFilePath);
try {
if (is != null) {
try {
serializationPolicy = SerializationPolicyLoader.loadFromStream(is,
null);
} catch (ParseException e) {
servlet.log("ERROR: Failed to parse the policy file '"
+ serializationPolicyFilePath + "'", e);
} catch (IOException e) {
servlet.log("ERROR: Could not read the policy file '"
+ serializationPolicyFilePath + "'", e);
}
} else {
String message = "ERROR: The serialization policy file '"
+ serializationPolicyFilePath
+ "' was not found; did you forget to include it in this deployment?";
servlet.log(message);
}
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// Ignore this error
}
}
}
return serializationPolicy;
}
}
Michele,
Thank you for the example servlet to handle this problem. However when I tried to use your approach it worked in the reverse proxy environment but not in my dev mode eclipse environment.
I took an approach that would let me seamlessly move between my dev and prod environments.
As you did I overwrote RemoteServiceServlet but I only replaced following...
#Override
protected SerializationPolicy doGetSerializationPolicy(
HttpServletRequest request, String moduleBaseURL, String strongName) {
//get the base url from the header instead of the body this way
//apache reverse proxy with rewrite on the header can work
String moduleBaseURLHdr = request.getHeader("X-GWT-Module-Base");
if(moduleBaseURLHdr != null){
moduleBaseURL = moduleBaseURLHdr;
}
return super.doGetSerializationPolicy(request, moduleBaseURL, strongName);
}
In my apache config I added...
ProxyPass /app/ ajp://localhost:8009/App-0.0.1-SNAPSHOT/
RequestHeader edit X-GWT-Module-Base ^(.*)/app/(.*)$ $1/App-0.0.1-SNAPSHOT/$2
This approach works in all scenarios and delegates the url "mucking" to apache's proxy settings which is the approach I've always taken.
Comments on this approach are appreciated
I'm fairly sure the correct answer here is to patch the source and submit a bug report. Another option would be to run the GWT app at / on your backend.
I'd prefer the former, but the latter should work too. If you really needed things separated out into multiple contexts, use a different port number?
I've run into a similar problem, a successful workaround was to make all serialized objects implement GWT's IsSerializable interface (in addition to the standard Serializable interface). If you read the message, it states that 'a legacy, 1.3.3 compatible, serialization policy will be used' - the 1.3.3 compatible policy requires all of your serialized objects implement the IsSerializable interface, so by adding it, everything worked.
I do have concerns that the legacy policy will be desupported in future versions of GWT, so i am also in search for a better workaround myself.
KC's answer is good. For those that do not want to muck around with apache configs, or need a quick and dirty way to test, here is a code only solution.
protected SerializationPolicy doGetSerializationPolicy(final HttpServletRequest request, String moduleBaseURL, final String strongName) {
final String moduleBaseURLHdr = request.getHeader("X-GWT-Module-Base");
if (moduleBaseURLHdr != null) {
moduleBaseURL = moduleBaseURLHdr.replace("foo/bar", "bar");
}
return super.doGetSerializationPolicy(request, moduleBaseURL, strongName);
}
The application is on http://server/bar, the proxy is serving it at http://proxy/foo/bar
Hence moduleBaseURL = moduleBaseURLHdr.replace("foo/bar", "bar"); makes GWT happy.
Likewise if the application is at http://server/bar and the proxy is serving at http://proxy/, you need to add bar to the moduleBaseURL (right before the package name).
This can be generalized through the use of getServletContext().getContextPath() etc...
My goal was to avoid additional header(s) which would make deployment and configuration harder. I solved this problem by overriding RemoteServiceServlet.doGetSerializationPolicy():
#Override
protected SerializationPolicy doGetSerializationPolicy(HttpServletRequest request, String moduleBaseURL, String strongName) {
String localServerAddress = "http://127.0.0.1:" + getThreadLocalRequest().getLocalPort();
String localContextPath = getServletConfig().getServletContext().getContextPath();
String moduleName = extractGwtModuleName(moduleBaseURL);
String localModuleBaseURL = joinPaths(localServerAddress, localContextPath, moduleName, "/");
return super.doGetSerializationPolicy(request, localModuleBaseURL, strongName);
}
In above code:
extractGwtModuleName() extracts last string prefixed and/or followed by slash
joinPaths() joins multiple url parts, removes unnecessary slashes
Use restful JSON for your RPC calls instead of GWT-RPC.
This solves the reverse-proxy problem since no serialization files are required.