Showing posts with label REST. Show all posts
I am currently developing some application in Swing which does a lot of crazy things, but it also connects to backend system via REST interfaces to retrieve or send some XML's. At this moment I must to admit that one of the most powerful libraries used by me to serialize and deserialize XML is nothing else that XStream [1]. It is really worth of using. Very powerful and configurable. It deserves to be described in separate post.
Back to the topic, I was looking for some HTTP client request library which can help me to make some requests to server in approachable way. On the one hand we have HttpClient supplied by Apache in httpcomponents package [2]. We have also RestTemplate supplied by Spring team [3] and so on. But this time I found library called Unirest! [4].
You can make GET, POST, PUT, PATCH, DELETE, HEAD and OPTIONS requests in synchronous or asynchronous way, supports form parameters, file uploads, gzip, Basic Authentication, timeouts, proxy, responses in String or JSON.
In this post I would like to present two mainly used at this moment in previously mentioned application, approaches to REST interfaces using of course GET and POST methods. There also be used Basic Authentication.
Firstly let's create interface for those methods :
public interface mQubeQueries { ListGETgetPlayers(Integer serviceId, Date from, Date to) throws UnirestException, XStreamException; void sendResults(Integer serviceId, Integer stageId, List results) throws UnirestException, XStreamException; }
public class mQubeQueriesImpl implements mQubeQueries { private XStream xStream; public mQubeQueriesImpl() { this.xStream = new XStream(); this.xStream.setMode(XStream.ID_REFERENCES); } @Override public ListgetPlayers(Integer serviceId, Date from, Date to) throws UnirestException, XStreamException { GetRequest response = Unirest.get("http://server.com/" + "get-players" + "/" + serviceId + "/" + new DateFormatter().formatQubeDateTimezone(from) + "/" + new DateFormatter().formatQubeDateTimezone(to)).basicAuth("login", "password"); if (response.asString().getStatus() == 403) { throw new UnirestException("No authorized"); } if (response.asString().getStatus() != 200) { throw new UnirestException("Unexpected response with code : " + response.asString().getStatus()); } String body = response.asString().getBody(); if (body == null) { throw new UnirestException("Response from server is null"); } else { try { return (List ) xStream.fromXML(body); } catch (Exception e) { throw new XStreamException(e.getMessage()); } } } }
@Override public void sendResults(Integer serviceId, Integer stageId, ListReferences :results) throws UnirestException, XStreamException { List results = new ArrayList (); for (Entrant entrant : results) { ResultDTO record = new ResultDTO(); record.setDateCreated(new Date()); results.add(record); } String xml = xStream.toXML(results); HttpResponse response = Unirest.post("http://server.com/" + "send-drawing-results" + "/" + serviceId + "/" + stageId).basicAuth("login", "password"). header("Content-Type", "application/xml").body(xml).asString(); if (response.getStatus() == 403) { throw new UnirestException("No authorized"); } if (response.getStatus() != 204) { throw new UnirestException("Unexpected response with code " + response.getStatus()); } }
[1] XStream
[2] HC Apache
[3] Spring RestTemplate
[4] Unirest
[5] Pastebin Interface Source Code
[6] Pastebin GET Method Source Code
[7] Pastebin POST Method Source Code
Sometimes there is a some particular need that your program (of course mainly written in Java, that's obvious) must also be able to work under Windows environment (sic!). There is no such problem if you program will have still .jar extension, but recently business in my company demanded to create such program with .exe extension. I was convinced that it's not really possible. I was thinking how to mix different approaches to create applications under Windows and Linux environment.
But I finally found a very helpful and customizable tool called Launch4j [1]. This tool is mainly used by Graphical User Interface (GUI) where you define all configuration for instance Input (jar) and Output file (exe), some classpath, header, JRE version required by application to work, some custom environment variables, splash and of course information about version, copyright, product and company name etc.
Regarding to my case in company I must transform .jar to .exe file without using GUI. There was a need to create some REST interface which will receive some parameters like .jar file, .icon and other specified information to generate generic .exe file using of course launch4j.
To do so, you must include launch4j.jar to your project and use below Java code to generate .exe.
public static void main(String[] args) { try { File file = new File("/home/lciesluk/configuration.xml");
try { ConfigPersister.getInstance().load(file); } catch (ConfigPersisterException ex) { System.out.println("ConfigPersisterException " + ex.getMessage()); } Config config = ConfigPersister.getInstance().getConfig(); System.out.println("Input : " + config.getJar().getAbsolutePath()); System.out.println("Output : " + config.getOutfile().getAbsolutePath()); File baseDir = new File("/home/lciesluk/launch4j"); //extracted launch4j Builder b = new Builder(Log.getAntLog(), baseDir); File build = b.build(); System.out.println("EXE location : " + build.getAbsolutePath()); } catch (BuilderException ex) { System.out.println("BuilderException " + ex.getMessage()); } }
I added also an additional sample of configuration file used by launch4j [2].
<launch4jconfig>
<dontwrapjar>false</dontwrapjar>
<headertype>gui</headertype>
<jar>/home/lukasz/Motohurt.jar</jar>
<outfile>/home/lukasz/Motohurt.exe</outfile>
<errtitle>Please download and install Java</errtitle>
<cmdline></cmdline>
<chdir>.</chdir>
<priority>normal</priority>
<downloadurl>http://java.com/download</downloadurl>
<supporturl></supporturl>
<stayalive>false</stayalive>
<restartoncrash>false</restartoncrash>
<manifest></manifest>
<icon>/home/lukasz/icon.ico</icon>
<jre>
<path></path>
<bundledjre64bit>false</bundledjre64bit>
<bundledjreasfallback>false</bundledjreasfallback>
<minversion>1.7.0</minversion>
<maxversion></maxversion>
<jdkpreference>preferJre</jdkpreference>
<runtimebits>64/32</runtimebits>
</jre>
<versioninfo>
<fileversion>1.0.0.0</fileversion>
<txtfileversion>1.0</txtfileversion>
<filedescription>App</filedescription>
<copyright>GarciaPL</copyright>
<productversion>1.0.0.0</productversion>
<txtproductversion>1.0</txtproductversion>
<productname>App</productname>
<companyname>GarciaPL</companyname>
<internalname>GarciaPL</internalname>
<originalfilename>App.exe</originalfilename>
</versioninfo>
</launch4jconfig>
Reference : [1] Launch4j Home Page [2] Launch4j Configuration XML
Very fast guide how to use REST Template in Spring with SSL. It is just a few lines of code, but in some time it was very useful for me. This example is using Telco interfaces which allow to get subscriber location. Unfortunately this one is not available to the public.
public class LocationTelcoAPI { private RestTemplate restTemplate = new RestTemplate(); private String telco_location = "https://api.orange.pl/terminallocation/?msisdn={phone}"; private void enableSSL() { TrustManager[] trustAllCerts = new TrustManager[]{ new X509TrustManager() { public java.security.cert.X509Certificate[] getAcceptedIssuers() { return null; } public void checkClientTrusted( java.security.cert.X509Certificate[] certs, String authType) { } public void checkServerTrusted( java.security.cert.X509Certificate[] certs, String authType) { } } }; try { SSLContext sc = SSLContext.getInstance("SSL"); sc.init(null, trustAllCerts, new java.security.SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); } catch (Exception e) { } } public LocationResponse getLocation(String telephone_number) { enableSSL(); String auth = TelcoAuth.USERNAME + ":" + TelcoAuth.PASSWORD; byte[] encodedAuth = Base64.encodeBase64(auth.getBytes()); String authHeader = "Basic " + new String(encodedAuth); HttpHeaders headers = new HttpHeaders(); headers.set("Accept", "application/json"); headers.set("Authorization", authHeader); Mapvariables = new HashMap (1); variables.put("phone", telephone_number); ResponseEntity exchange = restTemplate.exchange(telco_location, HttpMethod.GET, new HttpEntity (headers), LocationResponse.class, variables); System.out.println(exchange.getStatusCode()); System.out.println(exchange.getBody().getResult()); System.out.println(exchange.getBody().getLongitude()); System.out.println(exchange.getBody().getLatitude()); System.out.println(exchange.getBody().getAccuracy()); System.out.println(exchange.getBody().getAltitude()); System.out.println(exchange.getBody().getTimestamp()); return exchange.getBody(); } }
And class which help to deserialization XML :
@XmlRootElement(name = "response") public class LocationResponse { @XmlElement private String result; @XmlElement private String latitude; @XmlElement private String longitude; @XmlElement private String altitude; @XmlElement private String accuracy; @XmlElement private String timestamp; public LocationResponse() { } public LocationResponse(String result, String latitude, String longitude, String altitude, String accuracy, String timestamp) { this.result = result; this.latitude = latitude; this.longitude = longitude; this.altitude = altitude; this.accuracy = accuracy; this.timestamp = timestamp; } public String getResult() { return result; } public String getLatitude() { return latitude; } public String getLongitude() { return longitude; } public String getAltitude() { return altitude; } public String getAccuracy() { return accuracy; } public String getTimestamp() { return timestamp; } @Override public String toString() { return "LocationResponse{" + "result=" + result + ", latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + ", accuracy=" + accuracy + ", timestamp=" + timestamp + '}'; } }
UPDATE According to Abhijit comment, we can use ClientHttpRequestFactory used as a parameter in RestTemplate constructor. Just implement a ClientHttpRequestFactory and override the prepareConnection method to achieve the same effect as above, but with limiting customers of your system instead of sharing it globally with everyone [3].
Reference :
[1] Source Pastebin Main Class
[2] Source Pastebin XML Deserialization
[3] ClientHttpRequestFactory Example