I am using the Jersey client to run some integration tests against my service. However, one of my calls sends a redirect. I am expecting to get a redirect but when Jersey Client gets the redirect it errors out with a com.sun.jersey.api.client.UniformInterfaceException. Is there some way to make it accept the response with the redirect and just let me know what it got?
You can catch UniformInterfaceException which provides response field containing all the details.
You could additionally write some hamcrest matchers to express your expectations:
import static javax.ws.rs.core.Response.Status.*;
import static org.junit.rules.ExpectedException.*;
import javax.ws.rs.core.Response.Status;
import org.hamcrest.*;
import org.junit.*;
import org.junit.rules.ExpectedException;
import com.sun.jersey.api.client.*;
public class MyResourceShould {
#Rule
public ExpectedException unsuccessfulResponse = none();
private WebResource resource;
#Before
public void setUp() {
Client client = Client.create();
client.setFollowRedirects(false);
resource = client.resource("http://example.com");
}
#Test
public void reportMovedPermanently() {
unsuccessfulResponse.expect(statusCode(MOVED_PERMANENTLY));
resource.path("redirecting").get(String.class);
}
public static Matcher<UniformInterfaceException> statusCode(Status status) {
return new UniformInterfaceExceptionResponseStatusMatcher(status);
}
}
class UniformInterfaceExceptionResponseStatusMatcher extends TypeSafeMatcher<UniformInterfaceException> {
private final int statusCode;
public UniformInterfaceExceptionResponseStatusMatcher(Status status) {
this.statusCode = status.getStatusCode();
}
public void describeTo(Description description) {
description.appendText("response with status ").appendValue(statusCode);
}
#Override
protected boolean matchesSafely(UniformInterfaceException exception) {
return exception.getResponse().getStatus() == statusCode;
}
}
Also note that follow redirects (in setUp method) should be set to false in order to get UniformInterfaceException instead of following redirect (if one is specified in Location header).
Related
I use thread local to store a user request specific features (ex. browser agent) it used to work fine on JAVA 7, but now after upgrading to JAVA 8 In some cases I see requests coming from android browser handled as if its coming from iOS browser even though it was detected correctly as android browser but later on while processing the request it was replaced with another thread local value! am not sure what am missing here can anyone help me? my environment setup (before/after) upgrade is:
tomcat 8 before and after.
JAVA upgraded from 7 to 8.
Spring upgraded from 4.1.7 to 4.2.5
Spring security upgraded from 3.2.3 to 4.03
I have a security filter that looks something like this:
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.web.filter.GenericFilterBean;
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
private final IdentityService identityService;
public AuthenticationTokenProcessingFilter(IdentityService userService) {
this.identityService = userService;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
SecurityManager.manager().clearManager();
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
String agent = httpRequest.getHeader("User-Agent");
SecurityManager.manager().setAgent(agent);
...
chain.doFilter(request, response);
}
}
And the Security manager looks like this:
import com.appseleon.platform.web.shared.CrossAppConstants;
public class SecurityManager {
private static SecurityManager manager;
private final ThreadLocal<String> agentContext = new ThreadLocal<String>();
private SecurityManager() {
manager = this;
}
public void clearManager() {
agentContext.set(null);
}
public static SecurityManager manager() {
return manager;
}
public String getAgent() {
String os = agentContext.get();
if (os == null) {
os = CrossAppConstants.DEFAULT_OS;
}
return os;
}
public void setAgent(String agent) {
System.out.println("### os detected: " + agent);
agentContext.set(agent);
}
}
Finally after setting the agent and in various areas of my code I call the SecurityManager to get the current user agent:
SecurityManager.manager().getAgent()
Can anyone help me figure out the cause of this issue, or even an alternative more reliable way to achieve this?
Thanks in advance :)
For starters your SecurityManager is flawed you should not get an instance but simply directly get/set the value on the ThreadLocal using static. Currently you might run into issues when things get loaded in a different class loader i.e. doesn't detect the singleton.
public abstract class SecurityManager {
private static final ThreadLocal<String> agentContext = new ThreadLocal<String>();
private SecurityManager() { }
public static void clearManager() {
agentContext.set(null);
}
public static String getAgent() {
String os = agentContext.get();
if (os == null) {
os = CrossAppConstants.DEFAULT_OS;
}
return os;
}
public static void setAgent(String agent) {
System.out.println("### os detected: " + agent);
agentContext.set(agent);
}
}
Then directly call the get/set methods on this.
In your filter you should wrap the filterChain.doFilter in a try / finally block in the finally always clear the thread local.
try {
chain.doFilter(request, response);
} finally {
SecurityManager.clearManager();
}
Also instead of extending GenericFilterBean you might want to extend OncePerRequestFilter which makes sure this functionality is only called once (especially useful if you have some forwards in your logic) and it works only for HttpServletRequest type of requests, saves you some code.
public class AuthenticationTokenProcessingFilter extends OncePerRequestFilter {
...
#Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse ress, FilterChain chain) throws IOException, ServletException {
String agent = req.getHeader("User-Agent");
SecurityManager.setAgent(agent);
...
try {
chain.doFilter(request, response);
} finally {
SecurityManager.clearManager();
}
}
}
This is also the way Spring Security works and Springs Transaction management for instance (with the static methods and shared ThreadLocal).
I have an object with state and non-serializable fields, like threads, and I would to invoke functions on it like one would do it through RMI but through http. I don't want to scale and I am in an isolated network. I am currently using Jetty, like this:
public class ObjectHandler extends AbstractHandler {
MyStatefulObject obj;
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String action = request.getParameter("action");
switch (action) {
case "method1":
obj.method1(request.getParameter("some-parameter"));
break;
case "method2":
obj.method2(request.getParameter("some-other-parameter"));
break;
}
baseRequest.setHandled(true);
}
}
which is kind of weird. I would like to use something like Servlets, and use the different methods to tell apart the action to do, or use JAX-RS to use the calling url to tell apart the action to do. But both of those methods are stateless, that is, I cannot pass an object to a servlet, and, at least with jersey, the construction was made with the class, not with and instance of it, so I could not control the construction of the MyStatefulObject object. So, is there a library for, let's say, annotate an object and pass it to a server instance and start listening to requests? I would like to make something like this:
#Path("/")
public class MyStatefulObject {
MyStatefulObject(Parameter param1, Param) {
//some building stuff
}
#POST
#Path("/path1")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8")
void method1(Parameter param) {}
#POST
#Path("/path2")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.APPLICATION_JSON + "; charset=UTF-8")
Object method2(Parameter param) {
return new Object();
}
}
while outside I would have:
Server server = new Server(8081);
server.setHandler(new MyStatefulObject(param));
server.start();
server.join();
Is there a library that makes me able to do that? as I say before, I don't want to scale (this is running in a small network) and there is no security concerns. I just want to "publish" an object.
In the end, Jersey does allow stateful objects to be published, using the ResourceConfig class with an object (as opposed with a Class, which is the use I found more frequently). Funny cause in this question they want to do the exact opposite. We simply register an object in the ResourceConfig.
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.net.URI;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import javax.inject.Singleton;
#Path("calculator")
public class Calculator {
int i = -1;
public Calculator(int i) {
this.i = i;
}
#GET
#Path("increment")
#Produces(MediaType.APPLICATION_JSON)
public String increment() {
i = i + 1;
return "" + i;
}
public static void main(String[] args) throws Exception {
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig.register(new Calculator(10));
Server server = JettyHttpContainerFactory.createServer(new URI("http://localhost:8080"), resourceConfig);
server.start();
}
}
I am working on Rest web services and client using CXF 3.1.2 , and i have few clarification as below,
Service:
import javax.jws.WebService;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
public class GenServiceImpl {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext) {
return "EventAgentLoggedIn";
}
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes({"application/xml", MediaType.TEXT_PLAIN})
#Path("/agentLogout")
public String agentLogout(String ext) {
return "EventAgentLoggedOut";
}
}
Client:
import javax.ws.rs.core.Response;
import org.apache.cxf.jaxrs.client.WebClient;
public class TestClient {
static final String REST_URI = "http://localhost:8080/RestfulSample/Restful";
public static void main(String[] args) {
WebClient client = WebClient.create(REST_URI);
//Get
client.path("agentLogin").path(new Integer(1234)).accept(MediaType.TEXT_PLAIN);
String agentLoginResponse = client.get(String.class);
System.out.println(agentLoginResponse);
client.reset();
//Post
client.path("agentLogout").accept(MediaType.TEXT_PLAIN);
Response agentLogoutResponse = client.post("10245");
System.out.println(agentLogoutResponse.readEntity(String.class));
client.reset();
}
Clarifications:
In my above example - In service class Post method(agentLogout) , i am getting error if i replace #Consumes({"application/xml", MediaType.TEXT_PLAIN})
with
#Consumes(MediaType.TEXT_PLAIN) whereas it works fine in Get method(agentLogin), may i know why it is so?
It is right to use client.reset(); - Here i am trying to use single WebClient to access all my methods.
Could you please let me know what i tried in my example is best practice ? and it will be appreciated if you could correct me here
Thanks,
Here are the clarifications.
Set content type to text/plain while posting. And you can set in your servers side class #Consumes(MediaType.TEXT_PLAIN)
client.replaceHeader("Content-Type",MediaType.TEXT_PLAIN);
Yes you can use rest method, here is java doc
When reusing the same WebClient instance for multiple invocations,
one may want to reset its state with the help of the reset() method,
for example, when the Accept header value needs to be changed and the
current URI needs to be reset to the baseURI (as an alternative to a
back(true) call). The resetQuery() method may be used to reset the
query values only. Both options are available for proxies too.
I would prefer to use proxy and access REST more like OOPS.
You could create interface for the above server class(Generally I careate REST definition as interface and then implement the interface( more like SOAP way)), which could be auto generated using WADLToJava maven plugin from WADL.
Here is sample interface for above server side rest class
public interface GenService {
#GET
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogin/{ext}")
public String agentLogin(#PathParam("ext") Integer ext);
#POST
#Produces(MediaType.TEXT_PLAIN)
#Consumes(MediaType.TEXT_PLAIN)
#Path("/agentLogout")
public String agentLogout(String ext);
}
Since you are not using spring , I will create a singleton class
public class CxfRestSingleton {
public static GenService obj;
public static GenService getInstance() {
if (obj == null) {
obj = JAXRSClientFactory.create("http://localhost:8080/RestfulSample/Restful", GenService.class);
}
return obj;
}
}
And you can access the rest using below code.
public static void main( String[] args )
{
System.out.println( CxfRestSingleton.getInstance().agentLogin(12345));
}
RESTEasy provides the Server-side Mock Framework for mocking server requests. Is there an equivalent for unit testing the client framework?
Is InMemoryClientExecutor intended for this purpose? I'm having trouble finding documentation and examples of how this class should be used.
Looks like InMemoryClientExecutor may be used for client-side mocking. Looking in the source, it internally uses the same classes as the server-side mock framework, namely, MockHttpRequest and MockHttpResponse.
InMemoryClientExecutor gives you the ability to override createResponse for mocking responses and also has a constructor which takes a Dispatcher, if you want to customize and intercept calls that way.
Here's a quick and dirty snippet leveraging the client framework example,
import javax.ws.rs.*;
import javax.ws.rs.core.Response.*;
import org.jboss.resteasy.client.*;
import org.jboss.resteasy.client.core.*;
import org.jboss.resteasy.client.core.executors.*;
import org.jboss.resteasy.mock.*;
import org.jboss.resteasy.plugins.providers.*;
import org.jboss.resteasy.spi.*;
public class InMemoryClientExecutorExample {
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);
}
public static void main(String[] args) {
RegisterBuiltin.register(ResteasyProviderFactory.getInstance());
ClientExecutor executor = new InMemoryClientExecutor() {
#Override
protected BaseClientResponse<?> createResponse(ClientRequest request, MockHttpResponse mockResponse) {
try {
System.out.println("Client requesting " + request.getHttpMethod() + " on " + request.getUri());
}
catch(Exception ex) {
ex.printStackTrace();
}
mockResponse.setStatus(Status.OK.getStatusCode());
return super.createResponse(request, mockResponse);
}
};
SimpleClient client = ProxyFactory.create(SimpleClient.class, "http://localhost:8081", executor);
client.putBasic("hello world");
}
}
I did some TDDs before, but they were just straightforward and simple.
However, I will implement a restful client and invoke a restful API of third parties (Twitter, or Jira).
I used Resteasy client framework to implement that. The code is:
public void invokePUT() {
ClientRequest request =
new ClientRequest("http://example.com/customers");
request.accept("application/xml");
ClientResponse<Customer> response = request.put(Customer.class);
try {
if (response.getStatus() != 201)
throw new RuntimeException("Failed!");
} finally {
response.releaseConnection();
}}
If I want to write a test for this method (should write test before implement this method), what kind of the code should I write.
For GET, I can test the return Entity is equals to my expected entity and for POST, I can test the created entity's id is not null.
But how about for PUT and DELETE. Thanks.
Try to use REST Assured testing framework. It is great tool for testing REST services. On their website you'll find tons of examples how to use it. Just use it together with JUnit or TestNG to check assertions and you are done.
Here's how I'd go about the problem in the short term:
1) Extract the request into a parameter to the method. invokePUT() now becomes:
public void invokePUT(ClientRequest request) {
request.accept("application/xml");
ClientResponse<Customer> response = request.put(Customer.class);
try {
if (response.getStatus() != 201)
throw new RuntimeException("Failed!");
} finally {
response.releaseConnection();
}
}
2) In your test, use a stubbed version of ClientRequest
#Test
public void sendsPayloadAsXml() {
StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse());
restApi.invokePUT(request);
assertEquals("application/xml", request.acceptHeader);
}
#Test
public void makesTheCallUsingPut() {
StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse());
restApi.invokePUT(request);
assertTrue(request.putWasCalled);
}
#Test
public void releasesTheConnectionWhenComplete() {
StubbedResponse success = new StubbedResponse();
StubbedClientRequest request = new StubbedClientRequest(success);
restApi.invokePUT(request);
assertTrue(success.connectionWasClosed);
}
#Test(expected = RuntimeException.class)
public void raisesAnExceptionWhenInvalidResponseReceived() {
StubbedClientRequest request = new StubbedClientRequest(new StubbedResponse(400));
restApi.invokePUT(request);
}
private static class StubbedClientRequest extends ClientRequest {
public String acceptHeader = "";
public boolean putWasCalled;
public ClientResponse response
public StubbedRequest(ClientResponse response) {
this.response = response;
}
#Override
public ClientResponse put(Class klass) {
putWasCalled = true;
return response;
}
#Override
public void accept(String header) {
acceptHeader += header;
}
}
private static class StubbedResponse extends ClientResponse {
public boolean connectionWasReleased;
public int status = 201;
public StubbedResponse(int status) {
this.status = status;
}
public StubbedResponse() { }
}
This may not be a perfect design (Handing the ClientRequest to the class and having the RestEasy stuff exposed to the outside world) but it's a start.
Hope that helps!
Brandon
i would inject mocked classes that test, if put and delete was called as intended (with expected parameters and so on). easymock or similar is good for that
(same with post and get)
EDIT:
in case you want to test the rest client, use dependency injection to inject the request, then use easymock to mock it like this (for example to test, if delete is called properly):
#Test void myTest(){
ClientRequest mock = EasyMock.createMock(ClientRequest.class);
mock.delete(2); //test if resource with id=2 is deleted or something similar
EasyMock.replay(mock);
invokeDelete(mock);
EasyMock.verify(mock);
}