I have three or more types of request that come in form of JSON data and convert to object.
Let's say that there is a request:
{
"id":1,
"type":"0",
"url":
"http://stackoverflow.com"
}
And I want to build some sort of conncetion factory that allows me to get pages like that:
Request request = new Request(json);
Response response = request.execute();
Of course the execute method has different implementation for each of the request's types.
I have a prototype that is written in plain JavaSE and I want to migrate to Spring Framework and also get some feedback about my code if it has problems. First of all I built a SimpleRequest that just obtains the page and returns the body.
class SimpleRequest implements Request{
Package requestData;
#Override
public Connection.Response execute() throws IOException {
Connection.Response response = Jsoup
.connect(requestData.getUrl())
.execute();
return response;
}
public void bind(Package requestData){
this.requestData = requestData;
}
}
This method just fetch the page. Nothing interesting.
Also I have RequestTemplate that prepare request:
class RequestTemplate{
Package requestData;
RequestFactory requestFactory = new RequestFactory();
Request request;
public RequestTemplate(Package requestData){
this.requestData = requestData;
try {
request = requestFactory.getRequestInstance(requestData.getType());
request.bind(requestData);
}catch (Exception e){
e.printStackTrace();
}
}
public Connection.Response execute(){
Connection.Response connection = null;
try{
connection = request.execute();
}catch (Exception e){
e.printStackTrace();
}
return connection;
}
}
This method obtains an object based of RequestType;
And of course I have RequestFactory that has a description of objects and create new Instances of them.
class RequestFactory{
public Request getRequestInstance(RequestType type) throws Exception {
switch (type){
case SIMPLE:
return new SimpleRequest();
default:
throw new Exception("Error");
}
}}
So we check the RequestType type matching with the enum list and return new instance.
I also what to implement something like that in my small project that are based on Spring Framework and there are two issues.
As I understand the code above is a bit messy and has some performance problems. I think that I'll use the code to serve lots of connection so that I have to optimize it somehow because of memory limit and so on.
Integration with Spring. It's a framework so I think there should be some features that could make my life easier. I've read about FactoryBean, but haven't caught how to wire it with my task. As I mentioned above that the code is a bit messy and i think that i created to much abstraction.
Thanks.
Related
I have created a custom extension (Connector), which sends an HttpRequest (using org.mule.runtime.http.api.client.HttpClient and the related classes).
The extension's unit tests file contains the following test, to which I've added a simple Mockito mock to throw a TimeoutException when the HTTP request is being sent:
public class DemoOperationsTestCase extends MuleArtifactFunctionalTestCase {
/**
* Specifies the mule config xml with the flows that are going to be executed in the tests, this file lives in the test resources.
*/
#Override
protected String getConfigFile() {
return "test-mule-config.xml";
}
#Test
public void executeSayHiOperation() throws Exception {
HttpClient httpClient = mock(HttpClient.class);
HttpRequest httpRequest = mock(HttpRequest.class);
when(httpClient.send(any(HttpRequest.class), anyInt(), anyBoolean(), any(HttpAuthentication.class))).thenThrow(new TimeoutException());
String payloadValue = ((String) flowRunner("sayHiFlow").run()
.getMessage()
.getPayload()
.getValue());
assertThat(payloadValue, is("Hello Mariano Gonzalez!!!"));
}
}
The test should fail because the function should throw a TimeoutException, it is what I want for now.
The code that is being tested is as follows (redacted for convenience):
HttpClient client = connection.getHttpClient();
HttpResponse httpResponse = null;
String response = "N/A";
HttpRequestBuilder builder = HttpRequest.builder();
try {
httpResponse = client
.send(builder
.addHeader("Authorization", authorization)
.method("POST")
.entity(new ByteArrayHttpEntity("Hello from Mule Connector!".getBytes()))
.uri(destinationUrl)
.build(),
0, false, null);
response = IOUtils.toString(httpResponse.getEntity().getContent());
} catch (IOException e) {
e.printStackTrace();
throw new ModuleException(DemoError.NO_RESPONSE, new Exception("Failed to get response"));
} catch (TimeoutException e) {
e.printStackTrace();
throw new ModuleException(DemoError.NO_RESPONSE, new Exception("Connection timed out"));
}
But I always get the "Failed to get response" error message, which is what I get when I run the Connector with a nonexistent server, therefore the mock isn't working (it actually tries to send an HTTP request).
I am new to Java unit testing, so it might be a general mocking issue and not specific to MuleSoft - though I came across other questions (such as this one and this one), I tried the suggestions in the answers and the comments, but I get the same error. I even tried to use thenReturn instead of thenThrow, and I get the same error - so the mock isn't working.
Any idea why this is happening?
I'm calling a REST Service that returns a JSON String. It works, but I'm not sure how to handle the exceptions and return values. Here are my two methods I wrote:
public static String callRestService(String id) {
try {
URL url = new URL("http://"localhost:8080/rest/api/2/issue/" + id);
String basicAuth = ConnectionHelper.getServerAuthentication(serverConfig.get("authenticationType"),
serverConfig.get("username"), serverConfig.get("password"));
HttpURLConnection connection = ConnectionHelper.getHttpURLConnection(url, "GET", "Accept", basicAuth);
if (connection != null) {
InputStream responseStream = connection.getInputStream();
String response = StringHelper.convertInputStreamToString(responseStream);
connection.disconnect();
return response;
}
return "";
} catch (Exception e) {
return "";
}
}
public static HttpURLConnection getHttpURLConnection(URL url, String requestMethod, String requestProperty,
String authentication) {
try {
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
if (authentication != null && !authentication.isEmpty()) {
connection.addRequestProperty("Authorization", authentication);
}
connection.setRequestMethod(requestMethod);
connection.addRequestProperty(requestProperty, "application/json");
return connection;
} catch (Exception e) {
return null;
}
}
Is my return value and exception handling ok? Or is there a better way to do this?
For better client side handling you should have an Enum with return cases
for example if we are building a registration module your enum should be like the following :
public enum RestResponseEnum{
DONE(1,"done"),DUPLICATE_RECORD(2,"Sorry this is a duplicate record"),ERROR(3,"There is an error happened")
//Getter & Setter
private int code;
//Getter & Setter
private String msg;
private(int code,String msg){
this.code=code;
this.msg=msg;
}
public static String getAsJson(RestResponseEnum restResponseEnum){
JSONObject jsonObject=new JSONObject();
jsonObject.put("code", restResponseEnum.getCode());
jsonObject.put("message", restResponseEnum.getMsg());
return jsonObject.toString();
}
}
Use it like this :
{
// Your function code
if(registeredEmailIsFoundInDatabase){
return RestResponseEnum.getAsJson(RestResponseEnum.DUPLICATE_RECORD);
}
}
You should always faclitate and clearify the response to the client
you can see this methodology from dealing with most of apis like this one from github : https://api.github.com/users/any/any
If it is a proper REST service it will add additional information about a call in the http response code. So if it doesnt start with 2, there is no point in parsing the response body at all (in case there is no contract to return error details in the body).
How to handle your exception much depends on your current application. General rules of thumb are:
Log exceptions
Handle them on an appropriate level
Sometimes you need to ensure encapsulation and handle them where they occur, sometimes it's okay to rethrow them an catch them globally. E.g. you are using a framework like JSF, user has triggered an external service call, log the exception, rethrow it, catch it and inform the user about it without sharing too much technical details. Like:
Error: YOUR_ERROR_CODE has occured. Please contact technical support
if this keeps happening.
Example:
if (connection.getResponseCode().startsWith("2") {
// do stuff
// if any checked exception occurs here, add it to throws clause and let the caller catch it
}
else if connection.getResponseCode().equals("404") {
throw new EntityNotFoundRuntimeException(...);
}
...
But whether or not this solution is good for your case depends on your architecture.
I have made my rest web service code to start sever like this :
static final String BASE_URI = "http://10.236.51.14:9000/abcd/";
public static void main(String[] args) {
try {
HttpServer server = HttpServerFactory.create(BASE_URI);
server.start();
System.out.println("Press Enter to stop the server. ");
System.in.read();
server.stop(0);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
And in the rest web service I have made a basic code to receive 2 arguments and show their sum like this :
#GET
#Path("/add/{a}/{b}")
#Produces(MediaType.TEXT_XML)
public String add(#PathParam("a") double a, #PathParam("b") double b) {
return "<?xml version=\"1.0\"?>" + "<result>" + (a + b) + "</result>";
}
I want to send Json data (image) from my android app to this webservice but I don't know how to receive it in webservice and display it.
Here is the code from my android app. In this I have converted a bitmap to string using Base64. How should I send it to my webservice?
ByteArrayOutputStream baos = new ByteArrayOutputStream();
mybitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
String strBitMap = Base64.encodeToString(b, Base64.DEFAULT);
Any help will be appreciated :)
I have searched a lot but cant find appropriate code for my webservice to receive and display the json data. I am also struggling in sending this base64 string to the webservice in form of json.
Please help me out.
Best regards :)
I have a question: Does your example WebService work? I mean the one with the two arguments. If you call http://10.236.51.14:9000/abcd/add/1/2 in your browser does it display 3 correctly? If not you should have an ApplicationConfig containing your REST-interfaces. Those should be added as resource classes for example like this:
#ApplicationPath("api")
public class ApplicationConfig extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.addAll(addServiceClasses());
resources.addAll(addFilterClasses());
return resources;
}
private Set<Class<?>> addServiceClasses() {
// add all your REST-classes here
Set<Class<?>> resources = new HashSet<>();
resources.add(YourCalculatorRestServiceClass.class);
resources.add(YourImageConsumingRestServiceClass.class);
return resources;
}
private Set<Class<?>> addFilterClasses() {
// add all your filter classes here (if you have any)
Set<Class<?>> resources = new HashSet<>();
resources.add(YourAuthenticationFilterClass.class);
resources.add(OtherFilterClass.class);
return resources;
}
#Override
public Map<String, Object> getProperties() {
Map<String, Object> properties = new HashMap<>();
// in Jersey WADL generation is enabled by default, but we don't
// want to expose too much information about our apis.
// therefore we want to disable wadl (http://localhost:8080/service/application.wadl should return http 404)
// see https://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e9020 for details
properties.put("jersey.config.server.wadl.disableWadl", true);
// we could also use something like this instead of adding each of our resources
// explicitly in getClasses():
// properties.put("jersey.config.server.provider.packages", "com.nabisoft.tutorials.mavenstruts.service");
return properties;
}
}
That should make the deal and you should be able to call http://10.236.51.14:9000/abcd/api/add/1/2. ApplicationConfig is annotated with #Path("api"). That means all classes registered in this config have the root path http://your.server.address/api/.
Now to your problem. I assume your server is working and you can reach your Webservice /add/1/2 displaying the result 3 in your browser.
Now you need another service listening for a POST. I'd take your already prepared String as the posted body.
#Path("image")
public class ImageReceiverRestService {
#POST
public Response checkAssignable(String base64ImageString) {
// code here working with the base64ImageString
// response code according to whatever happened during your algorithm
return Response.ok().build();
}
}
For appropriate HTTP response codes see this Wikipedia article for a quick overview HTTP Status Codes
So now you'd need a corresponding client on your android app. For example:
public class ImageSendingRestClient {
private final static String SERVER_BASE_URI = "http://10.236.51.14:9000/abcd/api/";
private final static String API_ADDRESS = "image/";
public ImageSendingRestClient() {
}
#Override
public void sendImageStringForProcessing(String base64ImageString) throws Exception {
Entity<String> entity = Entity.json(base64ImageString);
Response response = ClientBuilder.newClient()
.target(SERVER_BASE_URI)
.path(API_ADDRESS)
.request()
.post(entity);
try {
if (response.getStatus() == Response.Status.OK.getStatusCode()) {
return;
}
if (response.getStatus() == Response.Status.NOT_FOUND.getStatusCode()) {
throw new Exception;
}
} finally {
response.close();
}
}
}
All dependencies needed are JAX-RS implementations like JAX-RS reference implementation Jersey. Maybe you should also check the Jersey Guide with many examples providing most of the information you need Jersey User Guide
I am developing application, with http client, and I wonder to make some elegant issue.
This is standard java http client whose work in background thread, and passing data by event's (witch realized by override methods). I have special class for background requests, that implements method sendRequest()
protected void sendRequest(final String url) {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
URI website = null;
try {
website = new URI(url);
} catch (URISyntaxException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
HttpGet request = new HttpGet();
request.setURI(website);
HttpResponse response = null;
try {
response = client.execute(request, httpContext);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
if (response != null)
{
HttpEntity entity = response.getEntity();
try {
InputStream is = entity.getContent();
if (Debug.isDebuggerConnected()==true)
{
String data = convertStreamToString(is);
int code = response.getStatusLine().getStatusCode();
if (httpEvent!=null)
httpEvent.HttpResponseArrived(data, code);
}
else
httpEvent.HttpResponseArrived(convertStreamToString(is),response.getStatusLine().getStatusCode());
}
catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
});
t.start();
}
And also child class, for API to web server, wich have methods like that:
public void getSomeData(SomeParams param)
{
sendRequest("http://xxx.yy"+gson.toJson(param));
httpEvent = new HttpHandler()
{
#Override
public void HttpResponseArrived(String data, int code)
{
switch (code)
{
case 200:
//some code
break;
case 401:
//some code
break;
}
}
};
}
And my question: how elegant to handle server errors, for example 401? I need to do this in one place, in method that sending requests - sendRequest(). At first sight it is very easy: just handle 401, and if it's because expired cookie - call method Login() (in my design, it's look like getSomeData). But I want, not just login again, I need to request data, that I failed to get because the error. Of course, I can implement calling Login() method in every switch, like this:
case 401:
{
Login(CurrentContext.AuthData.Login, CurrentContext.AuthData.Password);
break;
}
But the login event implemented in Login() method;
Also, I can just write sendRequest(string authdata), subscrube for HttpHandler and by recursion call method thats implements this code. But I thind, it's not very good decision.
I really hope, that somebody already solve this problem, and there is the way, to turn it's in beautiful code!
Thanks, if you could to read this to the end:)
As for answer not comment.
Try to use http client framework - I prefer Apache HTTPClient. It provides wide controll over request and responses. Moreover it supports most common methods like GET POST etc. Cookie management, redirection handling and SSL support is also provided. Don't invent something that is already invented.
HttpClient - use v4.x
I have a number of classes exposed as JAX-RS request "handlers", using javax.ws.rs.Path annotations. I want to add certain actions before every request and after each request. Also, I need to create a global application-wide exception handler, which will catch everything thrown by these handlers and protocol.
Is it possible to achieve this with standard JAX-RS without creating of a custom class inherited from com.sun.jersey.spi.container.servlet.ServletContainer (I'm using Jersey).
You can also use ExceptionMappers. This mechanism which catch the exception thrown by your service and convert it to the appropriate Response:
#Provider
public class PersistenceMapper implements ExceptionMapper<PersistenceException> {
#Override
public Response toResponse(PersistenceException arg0) {
if(arg0.getCause() instanceof InvalidDataException) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
...
}
}
}
For more information see:
JAX-RS using exception mappers
You could create a proxy RESTful service and use this as the entry point to all your other RESTful services. This proxy can receive requests, do any pre-processing, call the RESTful service required, process the response and then return something to the caller.
I have a set up like this in a project I've been working on. The proxy performs functions like authentication, authorisation and audit logging. I can go into further details if you like.
Edit:
Here is an idea of how you might want to implement a proxy that supports GET requests;
#Path("/proxy")
public class Proxy
{
private Logger log = Logger.getLogger(Proxy.class);
#Context private UriInfo uriInfo;
#GET
#Path("/{webService}/{method}")
public Response doProxy(#Context HttpServletRequest req,
#PathParam("webService") String webService,
#PathParam("method") String method)
{
log.debug("log request details");
//implement this method to work out the URL of your end service
String url = constructURL(req, uriInfo, webService, method);
//Do any actions here before calling the end service
Client client = Client.create();
WebResource resource = client.resource(url);
try
{
ClientResponse response = resource.get(ClientResponse.class);
int status = response.getStatus();
String responseData = response.getEntity(String.class);
log.debug("log response details");
//Do any actions here after getting the response from the end service,
//but before you send the response back to the caller.
return Response.status(status).entity(responseData).build();
}
catch (Throwable t)
{
//Global exception handler here
//remember to return a Response of some kind.
}
}
You can use filters to read and modify all requests and responses.