I am using jersey to generate http requests and I would like to be able to see the request before it is sent (for debugging purposes).
For example:
WebResource resource = client.resource(url);
resource.header("aa", "bb");
resource.getHeaders(); // Error: how can I do it?
thanks
You can use LoggingFilter, as shown here
You need to add init-params and then implement ContainerRequestFilter
Put it in your web.xml Please note that com.az.jersey.server.AuthFilter is your class that has implemented mentioned above interface.
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.sun.jersey.api.container.filter.LoggingFilter;com.az.jersey.server.AuthFilter</param-value>
</init-param>
public class AuthFilter implements ContainerRequestFilter {
/**
* Apply the filter : check input request, validate or not with user auth
*
* #param containerRequest
* The request from Tomcat server
*/
#Override
public ContainerRequest filter(ContainerRequest containerRequest) throws WebApplicationException {
//GET, POST, PUT, DELETE, ...
String method = containerRequest.getMethod();
// myresource/get/56bCA for example
String path = containerRequest.getPath(true);
return containerRequest;
}
Related
I have two POST methods and one DELETE in my resource. They have same path.
I annotated one of POSTs with #DefaultMethod, so when someone doesn't send correct Accept header, correct method will be selected. But this causes that when DELETE is called, cxf selects POST instead of correct delete method. Is there any workaround for this?
CXF version: 3.1.17
#DefaultMethod
#POST
#Consumes(MeasurementMediaType.MEASUREMENT_TYPE)
#Produces(MeasurementMediaType.MEASUREMENT_TYPE)
public Response post(MeasurementRepresentation measurementRepresentation, #HeaderParam(value = HttpHeaders.ACCEPT) String acceptHeader) URISyntaxException {
...
}
#POST
#Consumes(MEASUREMENT_COLLECTION_TYPE)
#Produces(MEASUREMENT_COLLECTION_TYPE)
public Response post(MeasurementCollectionRepresentation measurementCollectionRepresentation, #HeaderParam(value = HttpHeaders.ACCEPT) String acceptHeader) {
...
}
#DELETE
public Response delete(
#QueryParam("fragmentType") String fragmentType,
#QueryParam("source") String source,
#QueryParam("dateFrom") DateTime dateFrom,
#QueryParam("dateTo") DateTime dateTo,
#QueryParam("type") String type) {
...
}
java.lang.NullPointerException
at com.cumulocity.measurement.rest.resources.MeasurementCollectionResource.post(MeasurementCollectionResource.java:280)
Two things:
1) DefaultMethod appears not to refer to the default method to select, but the default HTTPMethod. So it's essentially overriding the httpmethod of your call. This is a CXF extension to JAX-RS, so you may be able to ask the CXF team to update the functionality or create a new annotation for your use case.
2) If I understand you correctly, you would like the first method to be called if someone sends the body of {"Hello" : "World"}? Wouldn't you then get errors when trying to construct your MeasurementRepresentation? If they send a bad request, why not let CXF respond with an appropriate HTTP error code?
I am trying to use Firebase Cloud Messaging by Google with the help of Jetty HTTP client:
public static final String FCM_URL = "https://fcm.googleapis.com/fcm/send";
public static final String FCM_KEY = "key=AAAA....";
private final HttpClient mHttpClient = new HttpClient();
private final CompleteListener mFcmListener = new CompleteListener() {
#Override
public void onComplete(Result result) {
if (result.isFailed()) {
// TODO delete FCM token in database for certain responses
}
}
};
mHttpClient.start();
mHttpClient.POST(FCM_URL)
.header(HttpHeader.AUTHORIZATION, FCM_KEY)
.content(new StringContentProvider(notificationStr), "application/json")
.send(mFcmListener);
My question is very simple, but I couldn't find the answer myself yet by looking at the StringContentProvider and its base classes -
If I need to set the request HTTP header for FCM:
Content-Type: application/json
then do I have to add the line:
.header(HttpHeader.CONTENT_TYPE, "application/json")
or will that class already do it for me?
A couple of points:
Yes, if you don't set content type header explicitly, it would be auto set based on the selected Content Provider.
By default, the StringContentProvider sets Content-Type to text/plain. To override, you need to use another constructor -
new StringContentProvider("application/json", content, StandardCharsets.UTF_8);
Request #setContent method auto sets Content-Type header to the provided value. Hence, you need not make any change to the code.
I have MVC client that invokes a WCF service. The MVC client needs to pass one custom header in httprequest. The MVC client is also using Unity for DI.
I have already gone through SO POST and others links but they are all suggesting to use message inspector and custom behavior(which might be the correct way) but i'm looking for quick and dirty way because this will be temporary solution.
// Unity type Registration
public static void RegisterTypes(IUnityContainer container)
{
container.RegisterType<IDocumentManagementChannel>(new PerRequestLifetimeManager(),
new InjectionFactory(f=> CreateDocumentManagementChannel()));
}
private static IDocumentManagementChannel CreateDocumentManagementChannel()
{
var factory = new ChannelFactory<IDocumentManagementChannel>("BasicHttpEndPoint");
var channel = factory.CreateChannel();
// How do i add HttpHeaders into channel here?
return channel
}
In the code above How do i add custom header after i create a channel?
1- Below code should send the soap header from MVC
string userName = Thread.CurrentPrincipal.Identity.Name;
MessageHeader<string> header = new MessageHeader<string>(userName);
OperationContext.Current.OutgoingMessageHeaders.Add(
header.GetUntypedHeader("String", "System"));
2- And this code should read it on WCF
string loginName = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>("String", "System");
3- As for the channel, i recommend you create your custom System.ServiceModel.ClientBase as follows:
public abstract class UserClientBase<T> : ClientBase<T> where T : class
{
public UserClientBase()
{
string userName = Thread.CurrentPrincipal.Identity.Name;
MessageHeader<string> header = new MessageHeader<string>(userName);
OperationContext.Current.OutgoingMessageHeaders.Add(
header.GetUntypedHeader("String", "System"));
}
}
4- Create a custom client class that inherits from UserClientBase and use the base channel internally to call your IxxService which is the T here.
Is it possible to register a DynamicFeature with an ResteasyClient (Proxy Framework) similar to what can be done on server side?
So something similar to this:
final ResteasyClient client = new ResteasyClientBuilder().build();
client.register(new MyDynamicFeature());
Where MyDynamicFeature implements DynamicFeature
I'm trying to figure out how to have a ClientResponseFilter check the http return status depending on the annotation that is present on the resource method, and the DynamicFeature appeared to be the most promising lead to get access to the ResourceInfo.
So essentially, I want to do something like this:
#POST
#Path("some/path/user")
#ExpectedHttpStatus(201) // <- this would have to be passed on somehow as expectedStatus
User createUser(User request);
And then in the ClientResponseFilter (or any other solution) something like this:
#Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
if (responseContext.getStatus() != expectedStatus) {
// explode
}
}
Cause in the ClientResponseFilter, I don't see any way to know what the resource method is that defined the REST call that the filter is currently analyzing.
And the problem is that the framework right now only checks whether the response status is success, it doesn't check whether it's 200 or 201 and we'd like to refine that.
Here are some articles that seems to explain something very similar, yet this doesn't seem to be working with the ClientResponseFilter / ResteasyClient:
Match Filter with specific Method through NameBinding on RESTeasy
What is the proper replacement of the Resteasy 3.X PreProcessInterceptor?
First of all, I can't take credit for the solution really, but I'm going to paste the answer here.
Also, you could ask why the heck we're doing this? Because we need / want to test that the service returns the right http status, but unfortunately the service we are testing does not always return the same http status for the same http method.
E.g. in the example below, the post returns HttpStatus.OK, and another post method of the same service could return HttpStatus.CREATED.
Here's the solution we ended up with, a combination of ClientResponseFilter:
import java.io.IOException;
import java.util.UUID;
import javax.ws.rs.client.ClientRequestContext;
import javax.ws.rs.client.ClientResponseContext;
import javax.ws.rs.client.ClientResponseFilter;
/**
* {#link ClientResponseFilter} which will handle setting the HTTP StatusCode property for use with
* {#link HttpStatusResponseInterceptor}
*/
public class HttpStatusResponseFilter implements ClientResponseFilter {
public static final String STATUS_CODE = "StatusCode-" + UUID.randomUUID();
#Override
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException {
requestContext.setProperty(STATUS_CODE, responseContext.getStatusInfo());
}
}
And ReaderInterceptor:
import java.io.IOException;
import java.lang.annotation.Annotation;
import javax.ws.rs.ServerErrorException;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.ReaderInterceptor;
import javax.ws.rs.ext.ReaderInterceptorContext;
/**
* {#link ReaderInterceptor} which will verify the success HTTP status code returned from the server against the
* expected successful HTTP status code {#link SuccessStatus}
*
* #see HttpStatusResponseFilter
*/
public class HttpStatusResponseInterceptor implements ReaderInterceptor {
#Override
public Object aroundReadFrom(ReaderInterceptorContext interceptorContext) throws ServerErrorException, IOException {
Status actualStatus = (Status) interceptorContext.getProperty(HttpStatusResponseFilter.STATUS_CODE);
if (actualStatus == null) {
throw new IllegalStateException("Property " + HttpStatusResponseFilter.STATUS_CODE + " does not exist!");
}
Status expectedStatus = null;
for (Annotation annotation : interceptorContext.getAnnotations()) {
if (annotation.annotationType() == SuccessStatus.class) {
expectedStatus = ((SuccessStatus) annotation).value();
break;
}
}
if (expectedStatus != null && expectedStatus != actualStatus) {
throw new ServerErrorException(String.format("Invalid status code returned. Expected %d, but got %d.",
expectedStatus.getStatusCode(), actualStatus.getStatusCode()), actualStatus);
}
return interceptorContext.proceed();
}
}
We register both those when we create the client:
final ResteasyClient client = new ResteasyClientBuilder().disableTrustManager().build();
client.register(new HttpStatusResponseFilter());
client.register(new HttpStatusResponseInterceptor());
And the SuccessStatus is an annotation that we use to annotate the methods that we want to specifically check, e.g. like that:
#POST
#Path("some/foobar")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#SuccessStatus(Status.OK)
Foobar createFoobar(Foobar foobar);
It's not possible to register a DynamicFeature in your client.
See the DynamicFeature documentation:
A JAX-RS meta-provider for dynamic registration of post-matching
providers during a JAX-RS application setup at deployment time.
Dynamic feature is used by JAX-RS runtime to register providers that
shall be applied to a particular resource class and method and
overrides any annotation-based binding definitions defined on any
registered resource filter or interceptor instance.
Providers implementing this interface MAY be annotated with #Provider
annotation in order to be discovered by JAX-RS runtime when scanning
for resources and providers. This provider types is supported only as
part of the Server API.
The JAX-RS Client API can be utilized to consume any Web service exposed on top of a HTTP protocol, and is not restricted to services implemented using JAX-RS.
Please note the JAX-RS Client API does not invoke the resource classes directly. Instead, it generates HTTP requests to the server. Consequently, you won't be able to read the annotations from your resource classes.
Update 1
I'm not sure if this will be useful for you, but since you would like to access the server resource classes from your client, it would be interesting to mention that Jersey provides a proxy-based client API (org.glassfish.jersey.client.proxy package).
The basic idea is you can attach the standard JAX-RS annotations to an interface, and then implement that interface by a resource class on the server side while reusing the same interface on the client side by dynamically generating an implementation of that using java.lang.reflect.Proxy calling the right low-level client API methods.
This example was extracted from Jersey documentation:
Consider a server which exposes a resource at http://localhost:8080. The resource can be described by the following interface:
#Path("myresource")
public interface MyResourceIfc {
#GET
#Produces("text/plain")
String get();
#POST
#Consumes("application/xml")
#Produces("application/xml")
MyBean postEcho(MyBean bean);
#GET
#Path("{id}")
#Produces("text/plain")
String getById(#PathParam("id") String id);
}
You can use WebResourceFactory class defined in this package to access the server-side resource using this interface. Here is an example:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://localhost:8080/");
MyResourceIfc resource = WebResourceFactory.newResource(MyResourceIfc.class, target);
String responseFromGet = resource.get();
MyBean responseFromPost = resource.postEcho(myBeanInstance);
String responseFromGetById = resource.getById("abc");
I'm not sure if RESTEasy provides something similar to it.
Update 2
RESTEasy also provides a proxy framework. See the documentation:
RESTEasy has a client proxy framework that allows you to use JAX-RS annotations to invoke on a remote HTTP resource. The way it works is that you write a Java interface and use JAX-RS annotations on methods and the interface. For example:
public interface SimpleClient {
#GET
#Path("basic")
#Produces("text/plain")
String getBasic();
#PUT
#Path("basic")
#Consumes("text/plain")
void putBasic(String body);
#GET
#Path("queryParam")
#Produces("text/plain")
String getQueryParam(#QueryParam("param") String param);
#GET
#Path("matrixParam")
#Produces("text/plain")
String getMatrixParam(#MatrixParam("param") String param);
#GET
#Path("uriParam/{param}")
#Produces("text/plain")
int getUriParam(#PathParam("param") int param);
}
RESTEasy has a simple API based on Apache HttpClient. You generate a proxy then you can invoke methods on the proxy. The invoked method gets translated to an HTTP request based on how you annotated the method and posted to the server. Here's how you would set this up:
Client client = ClientFactory.newClient();
WebTarget target = client.target("http://example.com/base/uri");
ResteasyWebTarget rtarget = (ResteasyWebTarget) target;
SimpleClient simple = rtarget.proxy(SimpleClient.class);
simple.putBasic("hello world");
Alternatively you can use the RESTEasy client extension interfaces directly:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://example.com/base/uri");
SimpleClient simple = target.proxy(SimpleClient.class);
simple.putBasic("hello world");
[...]
The framework also supports the JAX-RS locator pattern, but on the client side. So, if you have a method annotated only with #Path, that proxy method will return a new proxy of the interface returned by that method.
[...]
It is generally possible to share an interface between the client and server. In this scenario, you just have your JAX-RS services implement an annotated interface and then reuse that same interface to create client proxies to invoke on the client-side.
Update 3
Since you are already using RESTEasy Proxy Framework and assuming your server resources implement the same interfaces you are using to create your client proxies, the following solution should work.
A ProxyFactory from Spring AOP, which is already packed with RESTEasy Client will do trick. This solution, basically, creates a proxy of the proxy to intercept the method that is being invoked.
The following class stores the Method instance:
public class MethodWrapper {
private Method method;
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
}
And the following code makes the magic:
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://example.com/api");
ExampleResource resource = target.proxy(ExampleResource.class);
MethodWrapper wrapper = new MethodWrapper();
ProxyFactory proxyFactory = new ProxyFactory(resource);
proxyFactory.addAdvice(new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
wrapper.setMethod(invocation.getMethod());
return invocation.proceed();
}
});
ExampleResource resourceProxy = (ExampleResource) proxyFactory.getProxy();
Response response = resourceProxy.doSomething("Hello World!");
Method method = wrapper.getMethod();
ExpectedHttpStatus expectedHttpStatus = method.getAnnotation(ExpectedHttpStatus.class);
int status = response.getStatus();
int expectedStatus = annotation.status();
For more information, have a look at the documentation:
MethodInterceptor
ProxyFactory
MethodInvocation
I am working on the Jboss Resteasy API to implement the REST services on Jboss server.I am new to this area. Can someone help me out here...
There is a Rest Service method with custom annotation(VRestAuto) like below.
#POST
#Produces("text/json")
#Path("/qciimplinv")
#Interceptors(VRestInterceptor.class)
public String getInvSummary(#VRestAuto("EnterpriseId") String enterpriseId,String circuitType){
....
businessMethod(enterpriseId,circuitType);
....
}
#VRestAuto annotation tell us 'enterpriseId' value is available in the user session.
User pass the circuitType alone as the POST parameter in the Rest Client tool.Should ideally read the enterpriseid from session and invoke the Rest service with these two parameters(enterpriseid,circuitType).
To achieve the above functionality, implemented the Interceptors class (VRestInterceptor) like below:
public class VRestInterceptor implemnets PreProcessInterceptor,AcceptedByMethod {
public boolean accept(Class declaring, Method method) {
for (Annotation[] annotations : method.getParameterAnnotations()) {
for (Annotation annotation : annotations) {
if(annotation.annotationType() == VRestAuto.class){
VRestAuto vRestAuto = (VRestAuto) annotation;
return vRestAuto.value().equals("EnterpriseId");
}
}
}
return false;
}
Override
public ServerResponse preProcess(HttpRequest request, ResourceMethod method)
throws Failure, WebApplicationException { ......}
}
I was able to verify the VRestAuto annotation in the accept method. But in the preProcess Method, how can I call the REST method with two parameters(enterpriseid, circuitType)?
if these interceptors are not suits, Are there any other interceptors best to this functionality?
Your help is highly appreciated .
Why not forget setting the enterpriseId value when the method is called and instead just inject the HttpServletRequest and use that to grab the session and value?
#POST
#Produces("text/json")
#Path("/qciimplinv")
public String getInvSummary(String circuitType, #Context HttpServletRequest servletRequest) {
HttpSession session = servletRequest.getSession();
String enterpriseId = session.getAttribute("EnterpriseId").toString();
....
businessMethod(enterpriseId,circuitType);
....
}