Skip to content

Commit 81bcacf

Browse files
authored
Merge pull request #2 from microsoftgraph/middleware
Add middlewares and BatchRequest capability to core library
2 parents f9acadc + ae3ced1 commit 81bcacf

16 files changed

+1019
-1
lines changed

build.gradle

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
// Apply the java-library plugin to add support for Java Library
1010
apply plugin: 'java-library'
11+
apply plugin: 'jacoco'
1112

1213
// In this section you declare where to find the dependencies of your project
1314
repositories {
@@ -27,6 +28,10 @@ dependencies {
2728
testImplementation 'junit:junit:4.12'
2829

2930
// Use Apache HttpClient
30-
compile 'org.apache.httpcomponents:httpclient:4.5.6'
31+
api 'org.apache.httpcomponents:httpclient:4.5.6'
32+
33+
// https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple
34+
compile group: 'com.googlecode.json-simple', name: 'json-simple', version: '1.1'
35+
3136
}
3237

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.microsoft.graph.content;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
import org.apache.http.Header;
9+
import org.apache.http.HttpEntity;
10+
import org.apache.http.HttpRequest;
11+
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
12+
import org.apache.http.util.EntityUtils;
13+
import org.json.simple.JSONObject;
14+
import org.json.simple.JSONValue;
15+
16+
public class MSBatchRequestContent {
17+
private List<MSBatchRequestStep> batchRequestStepsArray;
18+
private final int maxNumberOfRequests = 20;
19+
20+
public MSBatchRequestContent(List<MSBatchRequestStep> batchRequestStepsArray) {
21+
this.batchRequestStepsArray = new ArrayList<>();
22+
if(batchRequestStepsArray.size() <= maxNumberOfRequests) {
23+
for(MSBatchRequestStep requestStep: batchRequestStepsArray)
24+
addBatchRequestStep(requestStep);
25+
}
26+
}
27+
28+
public MSBatchRequestContent() {
29+
batchRequestStepsArray = new ArrayList<>();
30+
}
31+
32+
public boolean addBatchRequestStep(MSBatchRequestStep batchRequestStep) {
33+
if(batchRequestStep.getRequestId().compareTo("") == 0)
34+
return false;
35+
if(batchRequestStepsArray.size() == maxNumberOfRequests)
36+
return false;
37+
for(MSBatchRequestStep requestStep: batchRequestStepsArray) {
38+
if(batchRequestStep.getRequestId().compareTo(requestStep.getRequestId()) == 0)
39+
return false;
40+
}
41+
return batchRequestStepsArray.add(batchRequestStep);
42+
}
43+
44+
public boolean removeBatchRequesStepWithId(String requestId) {
45+
boolean ret = false;
46+
for (int i = batchRequestStepsArray.size()-1; i >= 0; i--)
47+
{
48+
MSBatchRequestStep requestStep = batchRequestStepsArray.get(i);
49+
for (int j = requestStep.getArrayOfDependsOnIds().size() - 1; j >= 0; j--)
50+
{
51+
String dependsOnId = requestStep.getArrayOfDependsOnIds().get(j);
52+
if(dependsOnId.compareTo(requestId) == 0)
53+
{
54+
requestStep.getArrayOfDependsOnIds().remove(j);
55+
ret = true;
56+
}
57+
}
58+
if(requestId.compareTo(requestStep.getRequestId()) == 0) {
59+
batchRequestStepsArray.remove(i);
60+
ret = true;
61+
}
62+
}
63+
return ret;
64+
}
65+
66+
public String getBatchRequestContent() {
67+
Map<String, List<Map<String, String>>> batchRequestContentMap = new HashMap<>();
68+
List<Map<String, String>> batchContentArray = new ArrayList<>();
69+
for(MSBatchRequestStep requestStep : batchRequestStepsArray) {
70+
batchContentArray.add(getBatchRequestMapFromRequestStep(requestStep));
71+
}
72+
batchRequestContentMap.put("requests", batchContentArray);
73+
return JSONValue.toJSONString(batchRequestContentMap);
74+
}
75+
76+
private Map<String, String> getBatchRequestMapFromRequestStep(MSBatchRequestStep batchRequestStep){
77+
Map<String, String> contentmap = new HashMap<>();
78+
contentmap.put("id", batchRequestStep.getRequestId());
79+
contentmap.put("url", batchRequestStep.getRequest().getRequestLine().getUri());
80+
contentmap.put("method", batchRequestStep.getRequest().getRequestLine().getMethod());
81+
Header[] headers = batchRequestStep.getRequest().getAllHeaders();
82+
if(headers != null && headers.length != 0) {
83+
JSONObject obj = new JSONObject();
84+
for(Header header: headers) {
85+
obj.put(header.getName(), header.getValue());
86+
}
87+
contentmap.put("headers", obj.toJSONString());
88+
}
89+
HttpEntity entity = null;
90+
HttpRequest request = batchRequestStep.getRequest();
91+
if(request instanceof HttpEntityEnclosingRequestBase) {
92+
HttpEntityEnclosingRequestBase httprequest = (HttpEntityEnclosingRequestBase)request;
93+
entity = httprequest.getEntity();
94+
}
95+
if(entity != null) {
96+
try {
97+
String body = EntityUtils.toString(entity);
98+
contentmap.put("body", body);
99+
}
100+
catch(Exception e) {
101+
e.printStackTrace();
102+
}
103+
}
104+
List<String> arrayOfDependsOnIds = batchRequestStep.getArrayOfDependsOnIds();
105+
if(arrayOfDependsOnIds != null) {
106+
contentmap.put("dependsOn", JSONValue.toJSONString(arrayOfDependsOnIds));
107+
}
108+
109+
return contentmap;
110+
}
111+
112+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.microsoft.graph.content;
2+
3+
import java.util.List;
4+
5+
import org.apache.http.HttpRequest;
6+
7+
public class MSBatchRequestStep {
8+
private String requestId;
9+
private HttpRequest request;
10+
private List<String> arrayOfDependsOnIds;
11+
12+
public MSBatchRequestStep(String requestId, HttpRequest request, List<String> arrayOfDependsOnIds) {
13+
this.requestId = requestId;
14+
this.request = request;
15+
this.arrayOfDependsOnIds = arrayOfDependsOnIds;
16+
}
17+
18+
public String getRequestId() {
19+
return requestId;
20+
}
21+
22+
public HttpRequest getRequest() {
23+
return request;
24+
}
25+
26+
public List<String> getArrayOfDependsOnIds(){
27+
return arrayOfDependsOnIds;
28+
}
29+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.microsoft.graph.content;
2+
3+
import org.apache.http.HttpEntity;
4+
import org.apache.http.HttpResponse;
5+
import org.apache.http.entity.ContentType;
6+
import org.apache.http.entity.StringEntity;
7+
import org.apache.http.message.BasicHttpResponse;
8+
import org.json.simple.JSONArray;
9+
import org.json.simple.JSONObject;
10+
import org.json.simple.parser.JSONParser;
11+
import org.json.simple.parser.ParseException;
12+
13+
public class MSBatchResponseContent {
14+
15+
private JSONObject batchResponseObj;
16+
17+
public MSBatchResponseContent(String batchResponseData ) {
18+
JSONParser parser = new JSONParser();
19+
try {
20+
if(batchResponseData != null)
21+
batchResponseObj = (JSONObject) parser.parse(batchResponseData);
22+
}
23+
catch(ParseException e) {
24+
e.printStackTrace();
25+
}
26+
}
27+
28+
public HttpResponse getResponseById(String requestId) {
29+
if(batchResponseObj == null)
30+
return null;
31+
32+
JSONArray responses = (JSONArray)batchResponseObj.get("responses");
33+
if(responses == null)
34+
return null;
35+
36+
for(Object response: responses) {
37+
JSONObject jsonresponse = (JSONObject)response;
38+
String id = (String)jsonresponse.get("id");
39+
if(id.compareTo(requestId) == 0) {
40+
HttpResponse httpresponse = new BasicHttpResponse(null, ((Long)jsonresponse.get("status")).intValue(), null);
41+
if(jsonresponse.get("body") != null) {
42+
HttpEntity entity = new StringEntity(jsonresponse.get("body").toString(), ContentType.APPLICATION_JSON);
43+
httpresponse.setEntity(entity);
44+
}
45+
if(jsonresponse.get("headers") != null){
46+
JSONObject jsonheaders = (JSONObject)jsonresponse.get("headers");
47+
for(Object key: jsonheaders.keySet()) {
48+
String strkey = (String)key;
49+
String strvalue = (String)jsonheaders.get(strkey);
50+
httpresponse.setHeader(strkey, strvalue);
51+
}
52+
}
53+
return httpresponse;
54+
55+
}
56+
}
57+
return null;
58+
}
59+
60+
public String getResponses() {
61+
if(batchResponseObj != null)
62+
return ((JSONArray)batchResponseObj.get("responses")).toJSONString();
63+
return null;
64+
}
65+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.microsoft.graph.httpcore;
2+
3+
import java.io.IOException;
4+
5+
import org.apache.http.HttpException;
6+
import org.apache.http.HttpRequest;
7+
import org.apache.http.HttpRequestInterceptor;
8+
import org.apache.http.protocol.HttpContext;
9+
10+
public class AuthenticationHandler implements HttpRequestInterceptor {
11+
12+
private IAuthenticationProvider authProvider;
13+
14+
public AuthenticationHandler(IAuthenticationProvider authProvider) {
15+
this.authProvider = authProvider;
16+
}
17+
18+
@Override
19+
public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
20+
String token = authProvider.getAccessToken();
21+
request.addHeader("Authorization", "Bearer " + token);
22+
}
23+
24+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.microsoft.graph.httpcore;
2+
3+
import org.apache.http.client.config.RequestConfig;
4+
import org.apache.http.impl.client.CloseableHttpClient;
5+
import org.apache.http.impl.client.HttpClientBuilder;
6+
7+
public class HttpClients {
8+
private HttpClients() {
9+
super();
10+
}
11+
12+
/**
13+
* Creates builder object for construction of custom
14+
* {@link CloseableHttpClient} instances.
15+
*/
16+
public static HttpClientBuilder custom() {
17+
return HttpClientBuilder.create();
18+
}
19+
20+
/**
21+
* Creates {@link CloseableHttpClient} instance with default
22+
* configuration and provided authProvider
23+
*/
24+
public static CloseableHttpClient createDefault(IAuthenticationProvider auth) {
25+
RequestConfig config = RequestConfig.custom().setMaxRedirects(5).build();
26+
27+
return HttpClientBuilder.create().addInterceptorFirst(new AuthenticationHandler(auth))
28+
.setRedirectStrategy(new RedirectHandler())
29+
.setServiceUnavailableRetryStrategy(new RetryHandler())
30+
.setDefaultRequestConfig(config)
31+
.build();
32+
}
33+
34+
/**
35+
* Creates {@link CloseableHttpClient} instance with default
36+
* configuration based on system properties.
37+
*/
38+
public static CloseableHttpClient createSystem() {
39+
return HttpClientBuilder.create().useSystemProperties().build();
40+
}
41+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.microsoft.graph.httpcore;
2+
3+
import org.apache.http.HttpRequest;
4+
5+
public interface IAuthenticationProvider {
6+
/**
7+
* Get Access Token
8+
*
9+
*/
10+
11+
String getAccessToken();
12+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package com.microsoft.graph.httpcore;
2+
3+
import java.net.URI;
4+
import java.net.URISyntaxException;
5+
6+
import org.apache.http.Header;
7+
import org.apache.http.HttpRequest;
8+
import org.apache.http.HttpResponse;
9+
import org.apache.http.HttpStatus;
10+
import org.apache.http.ProtocolException;
11+
import org.apache.http.client.methods.HttpGet;
12+
import org.apache.http.client.methods.HttpHead;
13+
import org.apache.http.client.methods.HttpUriRequest;
14+
import org.apache.http.client.methods.RequestBuilder;
15+
import org.apache.http.impl.client.DefaultRedirectStrategy;
16+
import org.apache.http.protocol.HttpContext;
17+
import org.apache.http.util.Args;
18+
19+
public class RedirectHandler extends DefaultRedirectStrategy{
20+
21+
public static final RedirectHandler INSTANCE = new RedirectHandler();
22+
23+
@Override
24+
public boolean isRedirected(
25+
final HttpRequest request,
26+
final HttpResponse response,
27+
final HttpContext context) throws ProtocolException {
28+
Args.notNull(request, "HTTP request");
29+
Args.notNull(response, "HTTP response");
30+
31+
final int statusCode = response.getStatusLine().getStatusCode();
32+
final Header locationHeader = response.getFirstHeader("location");
33+
if(locationHeader == null)
34+
return false;
35+
36+
if(statusCode == HttpStatus.SC_MOVED_TEMPORARILY ||
37+
statusCode == HttpStatus.SC_MOVED_PERMANENTLY ||
38+
statusCode == HttpStatus.SC_TEMPORARY_REDIRECT ||
39+
statusCode == HttpStatus.SC_SEE_OTHER ||
40+
statusCode == 308)
41+
return true;
42+
43+
return false;
44+
}
45+
46+
@Override
47+
public HttpUriRequest getRedirect(
48+
final HttpRequest request,
49+
final HttpResponse response,
50+
final HttpContext context) throws ProtocolException {
51+
final URI uri = getLocationURI(request, response, context);
52+
try {
53+
final URI requestURI = new URI(request.getRequestLine().getUri());
54+
if(!uri.getHost().equalsIgnoreCase(requestURI.getHost()) ||
55+
!uri.getScheme().equalsIgnoreCase(requestURI.getScheme()))
56+
request.removeHeaders("Authorization");
57+
}
58+
catch (final URISyntaxException ex) {
59+
throw new ProtocolException(ex.getMessage(), ex);
60+
}
61+
62+
final int status = response.getStatusLine().getStatusCode();
63+
if(status == HttpStatus.SC_SEE_OTHER)
64+
return new HttpGet(uri);
65+
return RequestBuilder.copy(request).setUri(uri).build();
66+
}
67+
}

0 commit comments

Comments
 (0)