Skip to content

Commit 78438c3

Browse files
committed
add client side async support
1 parent 2f12a2e commit 78438c3

File tree

12 files changed

+441
-29
lines changed

12 files changed

+441
-29
lines changed

src/main/java/com/emc/documentum/rest/client/sample/cases/ContentManagementSample.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ public void contentManagement() {
3333
printNewLine();
3434

3535
printStep("create a new rendition to the document");
36-
client.enableStreamingForNextRequest();
37-
client.createContent(createdObjectWithContent, "I'm the rendition content", "text/html", "primary", "false");
36+
client.enableStreamingForNextRequest().createContent(createdObjectWithContent, "I'm the rendition content", "text/html", "primary", "false");
3837
printHttpStatus();
3938
printNewLine();
4039

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
/*
2+
* Copyright (c) 2016. EMC Corporation. All Rights Reserved.
3+
*/
4+
package com.emc.documentum.rest.client.sample.cases;
5+
6+
import com.emc.documentum.rest.client.sample.client.DCTMRestClient;
7+
import com.emc.documentum.rest.client.sample.client.DCTMRestClientBuilder;
8+
import com.emc.documentum.rest.client.sample.client.annotation.RestServiceSample;
9+
import com.emc.documentum.rest.client.sample.model.Feed;
10+
import com.emc.documentum.rest.client.sample.model.FutureModel;
11+
import com.emc.documentum.rest.client.sample.model.RestObject;
12+
import com.emc.documentum.rest.client.sample.model.RestType;
13+
import com.emc.documentum.rest.client.sample.model.SearchFeed;
14+
import com.emc.documentum.rest.client.sample.model.batch.Capabilities;
15+
16+
import static com.emc.documentum.rest.client.sample.client.util.Debug.printStep;
17+
18+
@RestServiceSample("Simple async client")
19+
public class SimpleAsyncClientSample extends Sample {
20+
public void asyncCall() {
21+
printStep("build up async client based on the sync client");
22+
DCTMRestClient asyncClinet = DCTMRestClientBuilder.buildAsyncClient(client);
23+
24+
printStep("execute operations of DCTMRestClient like a normal sync clinet");
25+
Feed<RestObject> groups = asyncClinet.getGroups();
26+
27+
printStep("continue executing other operations without blocking");
28+
Feed<RestObject> cabinets = asyncClinet.getCabinets();
29+
Capabilities capabilities = asyncClinet.getBatchCapabilities();
30+
RestObject currentUser = asyncClinet.getCurrentUser();
31+
Feed<RestObject> users = asyncClinet.getUsers();
32+
33+
printStep("use the result as the normal DCTMRestClient response, but the operations on the result will be blocked until the async execution finished");
34+
System.out.println("there are " + groups.getEntries().size() + " gruops");
35+
36+
printStep("cast the response to the FutureModel, if wants to know more information");
37+
if(users instanceof FutureModel) {
38+
FutureModel futureUsers = (FutureModel)users;
39+
40+
printStep("check whether the execution finished");
41+
while(true) {
42+
boolean ready = futureUsers.isModelReady();
43+
System.out.println("isModelReady: " + ready);
44+
if(ready) {
45+
break;
46+
}
47+
try {
48+
Thread.sleep(10);
49+
} catch (InterruptedException e) {
50+
}
51+
}
52+
53+
printStep("or get the async call status and headers");
54+
System.out.println(futureUsers.getStatus());
55+
System.out.println(futureUsers.getHeaders());
56+
}
57+
58+
printStep("get the status and headers from the async client, will only return the latest operation's info, here is getUsers");
59+
System.out.println(asyncClinet.getStatus());
60+
System.out.println(asyncClinet.getHeaders());
61+
}
62+
63+
public void compareWithSync() {
64+
printStep("warm up");
65+
Feed<RestObject> cabinets = client.getCabinets();
66+
Feed<RestObject> users = client.getUsers();
67+
Feed<RestType> types = client.getTypes();
68+
Feed<RestObject> formats = client.getFormats();
69+
SearchFeed<RestObject> searches = client.search("test");
70+
71+
printStep("execute some requests syncly");
72+
long start = System.currentTimeMillis();
73+
cabinets = client.getCabinets();
74+
users = client.getUsers();
75+
types = client.getTypes();
76+
formats = client.getFormats();
77+
searches = client.search("test");
78+
long end = System.currentTimeMillis();
79+
System.out.println("sync execution costs " + (end - start) + " milliseconds");
80+
System.out.println("cabinets: " + cabinets.getEntries().size() +
81+
", users: " + users.getEntries().size() +
82+
", types: " + types.getEntries().size() +
83+
", formats: " + formats.getEntries().size() +
84+
", searches: " + searches.getEntries().size());
85+
86+
printStep("execute some requests asyncly");
87+
DCTMRestClient asyncClinet = DCTMRestClientBuilder.buildAsyncClient(client);
88+
start = System.currentTimeMillis();
89+
cabinets = asyncClinet.getCabinets();
90+
users = asyncClinet.getUsers();
91+
types = asyncClinet.getTypes();
92+
formats = asyncClinet.getFormats();
93+
searches = asyncClinet.search("test");
94+
end = System.currentTimeMillis();
95+
System.out.println("async execution costs " + (end - start) + " milliseconds");
96+
System.out.println("cabinets: " + cabinets.getEntries().size() +
97+
", users: " + users.getEntries().size() +
98+
", types: " + types.getEntries().size() +
99+
", formats: " + formats.getEntries().size() +
100+
", searches: " + searches.getEntries().size());
101+
}
102+
}

src/main/java/com/emc/documentum/rest/client/sample/client/DCTMRestClient.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
import org.springframework.http.HttpMethod;
1212
import org.springframework.http.HttpStatus;
1313

14+
import com.emc.documentum.rest.client.sample.client.annotation.ClientAsyncOption;
1415
import com.emc.documentum.rest.client.sample.client.annotation.NotBatchable;
16+
import com.emc.documentum.rest.client.sample.client.impl.AbstractRestTemplateClient.ClientType;
1517
import com.emc.documentum.rest.client.sample.model.Comment;
1618
import com.emc.documentum.rest.client.sample.model.Feed;
1719
import com.emc.documentum.rest.client.sample.model.FolderLink;
@@ -39,7 +41,7 @@
3941
* The sample REST client library
4042
*/
4143
@NotThreadSafe
42-
public interface DCTMRestClient {
44+
public interface DCTMRestClient extends Cloneable {
4345

4446
/**
4547
* @return the http headers of the previous operation
@@ -52,6 +54,12 @@ public interface DCTMRestClient {
5254
*/
5355
@NotBatchable
5456
public HttpStatus getStatus();
57+
58+
/**
59+
* @return the client type
60+
*/
61+
@NotBatchable @ClientAsyncOption(false)
62+
public ClientType getClientType();
5563

5664
/**
5765
* enable streaming for the binary content transfer.
@@ -60,43 +68,43 @@ public interface DCTMRestClient {
6068
* will be automatically disabled after the operation.
6169
* @return the DCTMRestClient itself
6270
*/
63-
@NotBatchable
71+
@NotBatchable @ClientAsyncOption(retainClient=true)
6472
public DCTMRestClient enableStreamingForNextRequest();
6573

6674
/**
6775
* @return the cached HomeDocument object
6876
*/
69-
@NotBatchable
77+
@NotBatchable @ClientAsyncOption(false)
7078
public HomeDocument getHomeDocument();
7179

7280
/**
7381
* @return the product info
7482
*/
75-
@NotBatchable
83+
@NotBatchable @ClientAsyncOption(false)
7684
public RestObject getProductInfo();
7785

7886
/**
7987
* @return the major version of the rest services
8088
*/
81-
@NotBatchable
89+
@NotBatchable @ClientAsyncOption(false)
8290
public double getMajorVersion();
8391

8492
/**
8593
* @return the cached Repositories feed
8694
*/
87-
@NotBatchable
95+
@NotBatchable @ClientAsyncOption(false)
8896
public Feed<Repository> getRepositories();
8997

9098
/**
9199
* @return the cached Repository object
92100
*/
93-
@NotBatchable
101+
@NotBatchable @ClientAsyncOption(false)
94102
public Repository getRepository();
95103

96104
/**
97105
* @return the current selected repository name
98106
*/
99-
@NotBatchable
107+
@NotBatchable @ClientAsyncOption(false)
100108
public String getCurrentRepositoryName();
101109

102110
/**
@@ -367,6 +375,7 @@ public interface DCTMRestClient {
367375
* @param uri the uri of the content media
368376
* @return the content in bytes
369377
*/
378+
@ClientAsyncOption(false)
370379
public byte[] getContentBytes(String uri);
371380

372381
/**

src/main/java/com/emc/documentum/rest/client/sample/client/DCTMRestClientBuilder.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
*/
44
package com.emc.documentum.rest.client.sample.client;
55

6+
import java.lang.reflect.Proxy;
67
import java.util.ArrayList;
78
import java.util.List;
89

910
import com.emc.documentum.rest.client.sample.client.impl.AbstractRestTemplateClient;
11+
import com.emc.documentum.rest.client.sample.client.impl.ClientAsyncRestTemplateClient;
1012
import com.emc.documentum.rest.client.sample.client.impl.jackson.DCTMJacksonClient;
1113
import com.emc.documentum.rest.client.sample.client.impl.jaxb.DCTMJaxbClient;
1214
import com.emc.documentum.rest.client.sample.client.util.Debug;
@@ -69,10 +71,18 @@ public static DCTMRestClient buildWithPrompt() {
6971
return client;
7072
}
7173

74+
/**
75+
* build the DCTMRestClient without the prompt
76+
* @return the DCTMRestClient
77+
*/
7278
public static DCTMRestClient buildSilently(DCTMRestClientBinding binding, String contextRoot, String repository, String username, String password) {
7379
return buildSilently(binding, contextRoot, repository, username, password, false, false, false);
7480
}
7581

82+
/**
83+
* build the DCTMRestClient without the prompt
84+
* @return the DCTMRestClient
85+
*/
7686
public static DCTMRestClient buildSilently(DCTMRestClientBinding binding, String contextRoot, String repository, String username, String password,
7787
boolean useFormatExtension, boolean debug, boolean enableCSRFClientToken) {
7888
boolean ignoreAuthenticateServer = ignoreAuthenticateServer(contextRoot);
@@ -94,6 +104,17 @@ public static DCTMRestClient buildSilently(DCTMRestClientBinding binding, String
94104
return client;
95105
}
96106

107+
/**
108+
* build the async DCTMRestClient
109+
* @return the DCTMRestClient
110+
*/
111+
public static DCTMRestClient buildAsyncClient(DCTMRestClient client) {
112+
if(!(client instanceof AbstractRestTemplateClient)) {
113+
throw new UnsupportedOperationException(client.getClass().getName());
114+
}
115+
return (DCTMRestClient)Proxy.newProxyInstance(DCTMRestClient.class.getClassLoader(), new Class[]{DCTMRestClient.class}, new ClientAsyncRestTemplateClient(100, client));
116+
}
117+
97118
private static List<String> getRepositories(DCTMRestClientBinding binding, String contextRoot) {
98119
DCTMRestClient client = new DCTMRestClientBuilder().bind(binding).contextRoot(contextRoot).build();
99120
Feed<Repository> repositories = client.getRepositories();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright (c) 2016. EMC Corporation. All Rights Reserved.
3+
*/
4+
package com.emc.documentum.rest.client.sample.client.annotation;
5+
6+
import java.lang.annotation.ElementType;
7+
import java.lang.annotation.Inherited;
8+
import java.lang.annotation.Retention;
9+
import java.lang.annotation.RetentionPolicy;
10+
import java.lang.annotation.Target;
11+
12+
@Target({ElementType.METHOD})
13+
@Retention(RetentionPolicy.RUNTIME)
14+
@Inherited
15+
public @interface ClientAsyncOption {
16+
boolean value() default false;
17+
boolean retainClient() default false;
18+
}

src/main/java/com/emc/documentum/rest/client/sample/client/impl/AbstractRestTemplateClient.java

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import com.emc.documentum.rest.client.sample.model.Entry;
4141
import com.emc.documentum.rest.client.sample.model.Feed;
4242
import com.emc.documentum.rest.client.sample.model.FeedBase;
43+
import com.emc.documentum.rest.client.sample.model.FutureModel;
4344
import com.emc.documentum.rest.client.sample.model.HomeDocument;
4445
import com.emc.documentum.rest.client.sample.model.LinkRelation;
4546
import com.emc.documentum.rest.client.sample.model.Linkable;
@@ -160,6 +161,8 @@ public HttpStatus getStatus() {
160161
return status;
161162
}
162163

164+
public abstract AbstractRestTemplateClient clone();
165+
163166
public AbstractRestTemplateClient debug(boolean debug) {
164167
this.debug = debug;
165168
return this;
@@ -175,8 +178,6 @@ protected void initRestTemplate(RestTemplate restTemplate) {
175178
restTemplate.getMessageConverters().add(new MultipartBatchHttpMessageConverter());
176179
}
177180

178-
public abstract ClientType getClientType();
179-
180181
private void setupHttp(ResponseEntity<?> entity) {
181182
if(entity == null) {
182183
headers = null;
@@ -300,7 +301,7 @@ protected <T> T sendRequest(String uri,
300301
}
301302
HttpEntity<Object> requestEntity = requestBody == null ?
302303
new HttpEntity<Object>(headers) :
303-
new HttpEntity<Object>(requestBody, headers);
304+
new HttpEntity<Object>(requestBody instanceof FutureModel?((FutureModel)requestBody).getModel():requestBody, headers);
304305
String requestUri = UriHelper.appendQueryString(uri, params);
305306
if(debug && noRequestProcessor) {
306307
Debug.debug("Sending " + httpMethod + " request to " + uri);
@@ -371,9 +372,9 @@ public double getMajorVersion() {
371372
*/
372373
protected RestObject newRestObject(RestObject oldObject, RestObject newObject) {
373374
try {
374-
return oldObject.getClass().getConstructor(RestObject.class).newInstance(newObject);
375+
return getModelClass(oldObject).getConstructor(RestObject.class).newInstance(newObject);
375376
} catch (Exception e) {
376-
throw new IllegalArgumentException(oldObject.getClass().getName());
377+
throw new IllegalArgumentException(getModelClass(oldObject).getName());
377378
}
378379
}
379380

@@ -460,12 +461,12 @@ public RestObject update(RestObject oldObject, LinkRelation rel, RestObject newO
460461
try {
461462
RestObject newRestObject = newRestObject(oldObject, newObject);
462463
if(method == PUT) {
463-
return put(oldObject.getHref(rel), newRestObject, newRestObject.getClass(), params);
464+
return put(oldObject.getHref(rel), newRestObject, getModelClass(newRestObject), params);
464465
} else {
465-
return post(oldObject.getHref(rel), newRestObject, newRestObject.getClass(), params);
466+
return post(oldObject.getHref(rel), newRestObject, getModelClass(newRestObject), params);
466467
}
467468
} catch (Exception e) {
468-
throw new IllegalArgumentException(oldObject.getClass().getName());
469+
throw new IllegalArgumentException(getModelClass(oldObject).getName());
469470
}
470471
}
471472

@@ -669,27 +670,38 @@ protected RestObject getCabinet(String cabinet, Class<? extends RestObject> claz
669670

670671
@Override
671672
public <T extends Linkable> T get(T t, String... params) {
672-
return (T)get(t.self(), t instanceof FeedBase, t.getClass(), params);
673+
return (T)get(t.self(), t instanceof FeedBase, getModelClass(t), params);
673674
}
674675

675676
@Override
676677
public <T extends Linkable> Feed<T> nextPage(Feed<T> feed) {
677-
return page(feed.getHref(PAGING_NEXT), feed.getClass());
678+
return page(feed.getHref(PAGING_NEXT), getModelClass(feed));
678679
}
679680

680681
@Override
681682
public <T extends Linkable> Feed<T> previousPage(Feed<T> feed) {
682-
return page(feed.getHref(PAGING_PREV), feed.getClass());
683+
return page(feed.getHref(PAGING_PREV), getModelClass(feed));
683684
}
684685

685686
@Override
686687
public <T extends Linkable> Feed<T> firstPage(Feed<T> feed) {
687-
return page(feed.getHref(PAGING_FIRST), feed.getClass());
688+
return page(feed.getHref(PAGING_FIRST), getModelClass(feed));
688689
}
689690

690691
@Override
691692
public <T extends Linkable> Feed<T> lastPage(Feed<T> feed) {
692-
return page(feed.getHref(PAGING_LAST), feed.getClass());
693+
return page(feed.getHref(PAGING_LAST), getModelClass(feed));
694+
}
695+
696+
@SuppressWarnings("unchecked")
697+
protected <T> Class<T> getModelClass(T model) {
698+
if(model == null) {
699+
return null;
700+
}
701+
if(model instanceof FutureModel) {
702+
return (Class<T>)((FutureModel)model).getModelClass();
703+
}
704+
return (Class<T>)model.getClass();
693705
}
694706

695707
@SuppressWarnings({ "unchecked", "rawtypes" })

0 commit comments

Comments
 (0)