Skip to content
This repository was archived by the owner on Sep 4, 2020. It is now read-only.

Commit e114332

Browse files
authored
Merge pull request #36 from microsoftgraph/iambmelt/work
Release 1.2.0
2 parents fff0145 + ffc8052 commit e114332

File tree

208 files changed

+2312
-86
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

208 files changed

+2312
-86
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ repository {
1515
1616
dependency {
1717
// Include the sdk as a dependency
18-
compile('com.microsoft.graph:msgraph-sdk-android:1.1.+')
18+
compile('com.microsoft.graph:msgraph-sdk-android:1.2.+')
1919
2020
// Include the gson dependency
2121
compile('com.google.code.gson:gson:2.3.1')
@@ -84,6 +84,7 @@ For a more detailed documentation see:
8484

8585
* [Overview](docs/overview.md)
8686
* [Extensibility](docs/extensibility.md)
87+
* [Handling Open Types, PATCH support with `null` values](docs/additional_data.md)
8788
* [Collections](docs/collections.md)
8889
* [Errors](docs/errors.md)
8990
* [Contributions](docs/contributions.md)

docs/opentypes.md

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Working with Open Types
2+
The Microsoft Graph SDK for Android allows you to capture, inspect, modify, and export properties not captured by the SDK's built-in native entity definitions.
3+
4+
Suppose you have an `EntityType` describing a Vehicle:
5+
```xml
6+
<EntityType Name="vehicle" BaseType="your.namespace.entity" OpenType="true">
7+
<Property Name="make" Type="Edm.String" Unicode="false" />
8+
<Property Name="model" Type="Edm.String" Unicode="false" />
9+
<Property Name="modelYear" Type="Edm.Int32" />
10+
</EntityType>
11+
```
12+
13+
Represented as JSON, this object might take the following form:
14+
```json
15+
{
16+
"id": "9043ff12-6046-495f-8a0f-4a0f65a3f288",
17+
"make": "Chase Motor Truck Company",
18+
"model": "Model M",
19+
"modelYear": "1912"
20+
}
21+
```
22+
23+
As a native Java object, you might choose to implement this entity thusly:
24+
```java
25+
class Vehicle extends BaseEntity {
26+
String make;
27+
String model;
28+
Year modelYear;
29+
}
30+
```
31+
32+
Because `vehicle` is defined as an `OpenType`, additional undeclared properties may be sent by the web service: in this case, a license plate number.
33+
34+
```json
35+
{
36+
"id": "9043ff12-6046-495f-8a0f-4a0f65a3f288",
37+
"make": "Chase Motor Truck Company",
38+
"model": "Model M",
39+
"modelYear": "1912",
40+
"licensePlate": "MSGRAPH4U"
41+
}
42+
```
43+
44+
With the addition of the `AdditionalDataManager` (as of `v1.1.1`), capture and transmission of such properties is supported through a transient native property.
45+
46+
## Examples
47+
48+
### Querying undeclared properties
49+
Using the above example, we'll query our vehicle entity for the undeclared `licensePlate` property:
50+
51+
```java
52+
// Load a Vehicle
53+
Vehicle vehicle = getVehicleById("<some id>");
54+
55+
// Access the licensePlate property
56+
String licensePlate =
57+
vehicle
58+
.getAdditionalDataManager()
59+
.get("licensePlate")
60+
.getAsString();
61+
```
62+
63+
### Initialize undeclared properties
64+
To specify an undeclared property, the following syntax may be used:
65+
66+
```java
67+
vehicle
68+
.getAdditionalDataManager()
69+
.put("numberOfDoors", new JsonPrimitive(0));
70+
```
71+
72+
This syntax supports all null, object, array, and primitive JSON structures.

docs/overview.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,12 @@ graphServiceClient()
168168
}
169169
});
170170
```
171+
172+
## Setting properties to `null`
173+
To support PATCH operations involving `null` values, specify the property name you wish to nullify:
174+
175+
```java
176+
user
177+
.getAdditionalDataManager()
178+
.put("officeLocation", JsonNull.INSTANCE);
179+
```

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,6 @@ mavenRepoUrl = https://api.bintray.com/maven/microsoftgraph/Maven/msgrap
2222
mavenGroupId = com.microsoft.graph
2323
mavenArtifactId = msgraph-sdk-android
2424
mavenMajorVersion = 1
25-
mavenMinorVersion = 1
25+
mavenMinorVersion = 2
2626
mavenPatchVersion = 0
2727
nightliesUrl = http://dl.bintray.com/MicrosoftGraph/Maven
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.microsoft.graph.extensions;
2+
3+
import android.test.AndroidTestCase;
4+
5+
import junit.framework.Assert;
6+
7+
/**
8+
* These tests verify that manually-written classes are preserved from version-to-version.
9+
*
10+
* @author brianmel
11+
*/
12+
public class ManualExtensionsTests extends AndroidTestCase {
13+
14+
public void testChunkedUploadRequestPreserved() {
15+
final String className = "com.microsoft.graph.extensions.ChunkedUploadRequest";
16+
try {
17+
Class.forName(className);
18+
} catch (ClassNotFoundException e) {
19+
Assert.fail("Extension [" + className + "] not found.");
20+
}
21+
}
22+
23+
public void testChunkedUploadResultPreserved() {
24+
final String className = "com.microsoft.graph.extensions.ChunkedUploadResult";
25+
try {
26+
Class.forName(className);
27+
} catch (ClassNotFoundException e) {
28+
Assert.fail("Extension [" + className + "] not found.");
29+
}
30+
}
31+
}

graphsdk/src/androidTest/java/com/microsoft/graph/http/MockConnection.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
public class MockConnection implements IConnection {
1515

1616
private final ITestConnectionData mData;
17-
private HashMap<String, String> mHeaders = new HashMap<String, String>();
17+
private HashMap<String, String> mHeaders = new HashMap<>();
1818
private Boolean mFollowRedirects;
1919

2020
public MockConnection(ITestConnectionData data) {
@@ -28,7 +28,7 @@ public void setFollowRedirects(boolean followRedirects) {
2828

2929
@Override
3030
public void addRequestHeader(String headerName, String headerValue) {
31-
mHeaders.put(headerName,headerValue);
31+
mHeaders.put(headerName, headerValue);
3232
}
3333

3434
@Override
@@ -70,4 +70,10 @@ public String getRequestMethod() {
7070
public int getContentLength() {
7171
return mData.getJsonResponse().length();
7272
}
73+
74+
@Override
75+
public void setContentLength(int length) {
76+
// noop
77+
}
78+
7379
}

graphsdk/src/androidTest/java/com/microsoft/graph/http/MockHttpProvider.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ public <Result, BodyType> Result send(IHttpRequest request,
102102
return null;
103103
}
104104

105+
@Override
106+
public <Result, BodyType, DeserializeType> Result send(IHttpRequest request, Class<Result> resultClass, BodyType serializable, IStatefulResponseHandler<Result, DeserializeType> handler) throws ClientException {
107+
return null;
108+
}
109+
105110
void setConnectionFactory(final IConnectionFactory factory) {
106111
mConnectionFactory = factory;
107112
}
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) 2015 Microsoft Corporation
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
// ------------------------------------------------------------------------------
22+
23+
package com.microsoft.graph.concurrency;
24+
25+
26+
import com.microsoft.graph.concurrency.ChunkedUploadResponseHandler;
27+
import com.microsoft.graph.concurrency.IProgressCallback;
28+
import com.microsoft.graph.extensions.ChunkedUploadRequest;
29+
import com.microsoft.graph.extensions.ChunkedUploadResult;
30+
import com.microsoft.graph.extensions.IGraphServiceClient;
31+
import com.microsoft.graph.extensions.UploadSession;
32+
import com.microsoft.graph.options.Option;
33+
34+
import java.io.IOException;
35+
import java.io.InputStream;
36+
import java.security.InvalidParameterException;
37+
import java.util.List;
38+
39+
/**
40+
* ChunkedUpload service provider.
41+
*
42+
* @param <UploadType> The upload item type.
43+
*/
44+
public class ChunkedUploadProvider<UploadType> {
45+
46+
/**
47+
* The default chunk size for upload. Currently set to 5 MiB.
48+
*/
49+
private static final int DEFAULT_CHUNK_SIZE = 5 * 1024 * 1024;
50+
51+
/**
52+
* The required chunk size increment by OneDrive Service, which is 320 KiB.
53+
*/
54+
private static final int REQUIRED_CHUNK_SIZE_INCREMENT = 320 * 1024;
55+
56+
/**
57+
* The maximum chunk size for a single upload allowed by OneDrive service.
58+
* Currently the value is 60 MiB.
59+
*/
60+
private static final int MAXIMUM_CHUNK_SIZE = 60 * 1024 * 1024;
61+
62+
/**
63+
* The default retry times for a simple chunk upload if failure happened.
64+
*/
65+
private static final int MAXIMUM_RETRY_TIMES = 3;
66+
67+
/**
68+
* The client.
69+
*/
70+
private final IGraphServiceClient mClient;
71+
72+
/**
73+
* The input stream.
74+
*/
75+
private final InputStream mInputStream;
76+
77+
/**
78+
* The upload session url.
79+
*/
80+
private final String mUploadUrl;
81+
82+
/**
83+
* The stream size.
84+
*/
85+
private final int mStreamSize;
86+
87+
/**
88+
* The upload response handler.
89+
*/
90+
private final ChunkedUploadResponseHandler<UploadType> mResponseHandler;
91+
92+
/**
93+
* The counter for how many bytes read from input stream.
94+
*/
95+
private int mReadSoFar;
96+
97+
/**
98+
* Create the ChunkedUploadProvider
99+
*
100+
* @param uploadSession The initial upload session.
101+
* @param client The onedrive client.
102+
* @param inputStream The input stream.
103+
* @param streamSize The stream size.
104+
* @param uploadTypeClass The upload type class.
105+
*/
106+
public ChunkedUploadProvider(final UploadSession uploadSession,
107+
final IGraphServiceClient client,
108+
final InputStream inputStream,
109+
final int streamSize,
110+
final Class<UploadType> uploadTypeClass) {
111+
if (uploadSession == null) {
112+
throw new InvalidParameterException("Upload session is null.");
113+
}
114+
115+
if (client == null) {
116+
throw new InvalidParameterException("OneDrive client is null.");
117+
}
118+
119+
if (inputStream == null) {
120+
throw new InvalidParameterException("Input stream is null.");
121+
}
122+
123+
if (streamSize <= 0) {
124+
throw new InvalidParameterException("Stream size should larger than 0.");
125+
}
126+
127+
this.mClient = client;
128+
this.mReadSoFar = 0;
129+
this.mInputStream = inputStream;
130+
this.mStreamSize = streamSize;
131+
this.mUploadUrl = uploadSession.uploadUrl;
132+
this.mResponseHandler = new ChunkedUploadResponseHandler(uploadTypeClass);
133+
}
134+
135+
/**
136+
* Upload content to remote upload session based on the input stream.
137+
*
138+
* @param options The upload options.
139+
* @param callback The progress callback invoked during uploading.
140+
* @param configs The optional ocnfigs for the upload options, [0] should be the customized chunk
141+
* size and the [1] should be the maxRetry for upload retry.
142+
* @throws IOException The io exception happend during upload.
143+
*/
144+
public void upload(final List<Option> options,
145+
final IProgressCallback<UploadType> callback,
146+
final int... configs)
147+
throws IOException {
148+
int chunkSize = DEFAULT_CHUNK_SIZE;
149+
150+
if (configs.length > 0) {
151+
chunkSize = configs[0];
152+
}
153+
154+
int maxRetry = MAXIMUM_RETRY_TIMES;
155+
156+
if (configs.length > 1) {
157+
maxRetry = configs[1];
158+
}
159+
160+
if (chunkSize % REQUIRED_CHUNK_SIZE_INCREMENT != 0) {
161+
throw new IllegalArgumentException("Chunk size must be a multiple of 320 KiB");
162+
}
163+
164+
if (chunkSize > MAXIMUM_CHUNK_SIZE) {
165+
throw new IllegalArgumentException("Please set chunk size smaller than 60 MiB");
166+
}
167+
168+
byte[] buffer = new byte[chunkSize];
169+
170+
while (this.mReadSoFar < this.mStreamSize) {
171+
int read = this.mInputStream.read(buffer);
172+
173+
if (read == -1) {
174+
break;
175+
}
176+
177+
ChunkedUploadRequest request =
178+
new ChunkedUploadRequest(this.mUploadUrl, this.mClient, options, buffer, read,
179+
maxRetry, this.mReadSoFar, this.mStreamSize);
180+
ChunkedUploadResult result = request.upload(this.mResponseHandler);
181+
182+
if (result.uploadCompleted()) {
183+
callback.progress(this.mStreamSize, this.mStreamSize);
184+
callback.success((UploadType) result.getItem());
185+
break;
186+
} else if (result.chunkCompleted()) {
187+
callback.progress(this.mReadSoFar, this.mStreamSize);
188+
} else if (result.hasError()) {
189+
callback.failure(result.getError());
190+
break;
191+
}
192+
193+
this.mReadSoFar += read;
194+
}
195+
}
196+
}

0 commit comments

Comments
 (0)