Skip to content
This repository has been archived by the owner on Apr 16, 2024. It is now read-only.

Commit

Permalink
Implement response parser for EnhancedImplementation
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenochiavone committed May 29, 2021
1 parent 7a3cd3d commit 15b0f58
Show file tree
Hide file tree
Showing 8 changed files with 2,066 additions and 570 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

- Enable multiple implementations for Rastreio API
- Implement response parser for EnhancedImplementation

## [1.0.4] - 2020-08-15
### Changed
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/rastreio/DefaultImplementation.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ private static Request newRequest(String objectCode) {
* @param response response data to be parsed
* @return new tracking object
*/
public static TrackObject parseResponse(String objectCode, String response) {
private TrackObject parseResponse(String objectCode, String response) {
TrackObjectServiceType serviceType = TrackObjectServiceType.UNKNOWN;

try {
Expand Down
137 changes: 134 additions & 3 deletions src/main/java/rastreio/EnhancedImplementation.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package rastreio;

import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
Expand All @@ -17,12 +20,17 @@
import okhttp3.RequestBody;
import okhttp3.Response;
import okhttp3.ResponseBody;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

/**
* Enhanced implementation using OkHttp and Jsoup (from DefaultImplementation).
*/
public class EnhancedImplementation implements Implementation {
private static final OkHttpClient HTTP_CLIENT;
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss SSS");

static {
HTTP_CLIENT = new OkHttpClient.Builder()
Expand All @@ -47,8 +55,7 @@ public void onResponse(Call call, Response response) throws IOException {
}
try (ResponseBody responseBody = response.body()) {
// Parse response and notify listener about new tacking object
listener.onSuccess(DefaultImplementation.parseResponse(objectCode,
responseBody.string()));
listener.onSuccess(parseResponse(objectCode, responseBody.string()));
} catch (IOException e) {
listener.onFailure(new Exception("Rastreio.track: unable to fullfill HTTP request", e));
}
Expand All @@ -71,7 +78,7 @@ public TrackObject trackSync(String objectCode) throws IOException {
((InMemoryCookieJar) HTTP_CLIENT.cookieJar()).clear();
}
// Parse response and return new tacking object
return DefaultImplementation.parseResponse(objectCode, response.body().string());
return parseResponse(objectCode, response.body().string());
} catch (IOException e) {
throw new IOException("Rastreio.trackSync: unable to fullfill HTTP request", e);
}
Expand Down Expand Up @@ -101,6 +108,130 @@ private static Request newRequest(String objectCode) {
return request;
}

/**
* Parse response data and create new tracking object.
* @param objectCode tracking object code
* @param response response data to be parsed
* @return new tracking object
*/
private TrackObject parseResponse(String objectCode, String response) {
TrackObjectServiceType serviceType = TrackObjectServiceType.UNKNOWN;

try {
serviceType = TrackObjectServiceType.valueOf(objectCode.substring(0, 2));
} catch (Exception e) {
// ignore
}

TrackObject trackObject = new TrackObject();
trackObject.setCode(objectCode);
trackObject.setServiceType(serviceType);
trackObject.setError(Error.OBJECT_NOT_FOUND);
trackObject.setValid(false);
trackObject.setDelivered(false);

Document document = Jsoup.parse(response);
Elements elements = document.getElementsByClass("listEvent");

if (elements.isEmpty()) {
return trackObject;
}

ArrayList<TrackObject.Event> events = new ArrayList<TrackObject.Event>();

for (Element eventListItem : elements) {
elements = eventListItem.getElementsByTag("tr").first().getElementsByTag("td");

if (elements.size() != 2) {
System.out.println("Rastreio.parseResponse: couldn't find enough table data elements");
continue; // Skip invalid table row
}

final Element eventListFirstData = elements.first();
final Element eventListLastData = elements.last();

String eventListFirstDataHtml = eventListFirstData.html();
String[] eventListFirstDataPieces = eventListFirstDataHtml.trim().split("<br>");

if (eventListFirstDataPieces.length != 3) {
System.out
.println("Rastreio.parseResponse: couldn't parse first table data element properly");
continue; // Skip invalid table row
}

String eventDate = eventListFirstDataPieces[0].trim();
String eventTime = eventListFirstDataPieces[1].trim();

elements = eventListFirstData.getElementsByTag("label");

String locale = null;

if (!elements.isEmpty()) {
locale = elements.first().text().trim();
} else {
locale = eventListFirstDataPieces[2].trim();
}

String eventListLastDataHtml = eventListLastData.html();
String[] eventListLastDataPieces = eventListLastDataHtml.trim().split("<br>");

elements = eventListLastData.getElementsByTag("strong");

String description = null;

if (!elements.isEmpty()) {
// Get `strong` node content
description = elements.first().text().trim();
} else if (eventListLastDataPieces.length > 0) {
// Get first string element as event description
description = eventListLastDataPieces[0].trim();
}

if (description == null || description.isEmpty()) {
System.out
.println("Rastreio.parseResponse: couldn't parse last table data element properly");
continue; // Skip invalid table row
}

String details = null;

if (eventListLastDataPieces.length > 1
&& !eventListLastDataPieces[1].trim().startsWith("<!--")) {
// Get second string element as event details
details = eventListLastDataPieces[1].trim();
}

TrackObject.Event event = new TrackObject.Event();
event.setLocale(locale);
event.setDescription(description);
event.setDetails(details);
try {
event.setTrackedAt(DATE_FORMAT.parse(eventDate + " " + eventTime + ":00 000"));
} catch (ParseException e) {
System.out.println("Rastreio.parseResponse: couldn't parse event date and time properly");
continue; // Skip invalid table row
}

events.add(0, event);
}

if (events.isEmpty()) {
return trackObject;
}

TrackObject.Event first = events.get(0);
TrackObject.Event last = events.get(events.size() - 1);

trackObject.setError(Error.NO_ERROR);
trackObject.setValid(true);
trackObject.setEvents(events);
trackObject.setDelivered(last.getDescription().toLowerCase().contains("objeto entregue"));
trackObject.setPostedAt(first.getTrackedAt());
trackObject.setUpdatedAt(last.getTrackedAt());

return trackObject;
}

/**
* In memory cookie jar implementation.
* Inspired by https://github.com/square/okhttp/issues/2890#issuecomment-600171522.
Expand Down
Loading

0 comments on commit 15b0f58

Please sign in to comment.