Skip to content

Commit f80fcbd

Browse files
author
Martin Caslavsky
committed
Merge pull request #48 from martiner/jmi-ads
Introduce Warehouse and Dataload Processes API support
2 parents ec683e2 + 0b39c4e commit f80fcbd

Some content is hidden

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

50 files changed

+2159
-49
lines changed

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,26 @@ dataStoreService.upload("/dir/file.txt", new FileInputStream("file.txt"));
9494
InputStream stream = dataStoreService.download("/dir/file.txt");
9595
dataStoreService.delete("/dir/file.txt");
9696
```
97+
98+
### Warehouse API
99+
Manage warehouses - create, update, list and delete.
100+
```java
101+
WarehouseService warehouseService = gd.getWarehouseService();
102+
Warehouse warehouse = warehouseService.createWarehouse(new Warehouse("title", "authToken", "description"));
103+
String jdbc = warehouse.getJdbcConnectionString();
104+
105+
warehouse.setTitle("another Title");
106+
warehouse = warehouseService.updateWarehouse(warehouse);
107+
108+
Collection<Warehouse> warehouseList = warehouseService.listInstances();
109+
warehouseService.removeWarehouse(warehouse);
110+
```
111+
112+
### Dataload processes API
113+
Manage dataload processes - create, update, list, delete, and process executions - execute, get logs, ...
114+
```java
115+
ProcessService processService = gd.getProcessService();
116+
Process process = processService.createProcess(project, new Process('name', 'GRAPH'), new File('path/to/processdatadir')).get();
117+
ProcessExecutionDetail executionDetail = processService.executeProcess(new ProcessExecution(process, "myGraph.grf")).get();
118+
processService.getExecutionLog(executionDetail, new FileOutputStream("file/where/the/log/willbewritten");
119+
```

src/main/java/com/gooddata/AbstractService.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
*/
44
package com.gooddata;
55

6+
import static com.gooddata.Validate.notNull;
7+
import static java.lang.String.format;
8+
import static org.springframework.http.HttpMethod.GET;
9+
610
import org.codehaus.jackson.map.ObjectMapper;
711
import org.springframework.http.HttpHeaders;
812
import org.springframework.http.HttpStatus;
@@ -17,11 +21,9 @@
1721
import java.io.ByteArrayInputStream;
1822
import java.io.IOException;
1923
import java.io.InputStream;
24+
import java.io.OutputStream;
2025
import java.util.concurrent.TimeUnit;
2126

22-
import static com.gooddata.Validate.notNull;
23-
import static java.lang.String.format;
24-
import static org.springframework.http.HttpMethod.GET;
2527

2628
/**
2729
* Parent for GoodData services providing helpers for REST API calls and polling.
@@ -58,7 +60,7 @@ public AbstractService(RestTemplate restTemplate) {
5860
this.restTemplate = notNull(restTemplate, "restTemplate");
5961
}
6062

61-
final <T> T poll(final PollHandler<T> handler, long timeout, final TimeUnit unit) {
63+
final <R> R poll(final PollHandler<?,R> handler, long timeout, final TimeUnit unit) {
6264
notNull(handler, "handler");
6365
final long start = System.currentTimeMillis();
6466
while (true) {
@@ -77,15 +79,15 @@ final <T> T poll(final PollHandler<T> handler, long timeout, final TimeUnit unit
7779
}
7880
}
7981

80-
final <T> boolean pollOnce(final PollHandler<T> handler) {
82+
final <P> boolean pollOnce(final PollHandler<P,?> handler) {
8183
notNull(handler, "handler");
8284
final ClientHttpResponse response = restTemplate.execute(handler.getPollingUri(), GET, noopRequestCallback,
8385
reusableResponseExtractor);
8486

8587
try {
8688
if (handler.isFinished(response)) {
87-
final T data = extractData(response, handler.getResultClass());
88-
handler.setResult(data);
89+
final P data = extractData(response, handler.getPollClass());
90+
handler.handlePollResult(data);
8991
} else if (HttpStatus.Series.CLIENT_ERROR.equals(response.getStatusCode().series())) {
9092
throw new GoodDataException(
9193
format("Polling returned client error HTTP status %s", response.getStatusCode().value())
@@ -108,15 +110,18 @@ protected final <T> T extractData(ClientHttpResponse response, Class<T> cls) thr
108110

109111
private class ReusableClientHttpResponse implements ClientHttpResponse {
110112

111-
private final byte[] body;
113+
private byte[] body;
112114
private final HttpStatus statusCode;
113115
private final int rawStatusCode;
114116
private final String statusText;
115117
private final HttpHeaders headers;
116118

117119
public ReusableClientHttpResponse(ClientHttpResponse response) {
118120
try {
119-
body = FileCopyUtils.copyToByteArray(response.getBody());
121+
final InputStream bodyStream = response.getBody();
122+
if (bodyStream != null) {
123+
body = FileCopyUtils.copyToByteArray(bodyStream);
124+
}
120125
statusCode = response.getStatusCode();
121126
rawStatusCode = response.getRawStatusCode();
122127
statusText = response.getStatusText();
@@ -152,7 +157,7 @@ public HttpHeaders getHeaders() {
152157

153158
@Override
154159
public InputStream getBody() throws IOException {
155-
return new ByteArrayInputStream(body);
160+
return body != null ? new ByteArrayInputStream(body) : null;
156161
}
157162

158163
@Override
@@ -161,4 +166,17 @@ public void close() {
161166
}
162167
}
163168

169+
protected static class OutputStreamResponseExtractor implements ResponseExtractor<Integer> {
170+
private final OutputStream output;
171+
172+
public OutputStreamResponseExtractor(OutputStream output) {
173+
this.output = output;
174+
}
175+
176+
@Override
177+
public Integer extractData(ClientHttpResponse response) throws IOException {
178+
return FileCopyUtils.copy(response.getBody(), output);
179+
}
180+
}
181+
164182
}

src/main/java/com/gooddata/FutureResult.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public final class FutureResult<T> {
1414

1515
private final AbstractService service;
1616

17-
private final PollHandler<T> handler;
17+
private final PollHandler<?,T> handler;
1818

1919
/**
2020
* Creates a new instance of the result to be eventually retrieved by polling on the REST API.<p>
@@ -23,7 +23,7 @@ public final class FutureResult<T> {
2323
* @param service this service
2424
* @param handler poll handler
2525
*/
26-
public FutureResult(final AbstractService service, final PollHandler<T> handler) {
26+
public FutureResult(final AbstractService service, final PollHandler<?,T> handler) {
2727
this.service = notNull(service, "service");
2828
this.handler = notNull(handler, "handler");
2929
}

src/main/java/com/gooddata/GoodData.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
package com.gooddata;
55

66
import com.gooddata.account.AccountService;
7+
import com.gooddata.dataload.processes.ProcessService;
8+
import com.gooddata.warehouse.WarehouseService;
79
import com.gooddata.dataset.DatasetService;
810
import com.gooddata.gdc.DataStoreService;
911
import com.gooddata.gdc.GdcService;
@@ -59,6 +61,8 @@ public class GoodData {
5961
private final DataStoreService dataStoreService;
6062
private final DatasetService datasetService;
6163
private final ReportService reportService;
64+
private final ProcessService processService;
65+
private final WarehouseService warehouseService;
6266

6367
/**
6468
* Create instance configured to communicate with GoodData Platform under user with given credentials.
@@ -111,6 +115,8 @@ public GoodData(String hostname, String login, String password, int port, String
111115
dataStoreService = new DataStoreService(httpClientBuilder, gdcService, login, password);
112116
datasetService = new DatasetService(restTemplate, dataStoreService);
113117
reportService = new ReportService(restTemplate);
118+
processService = new ProcessService(restTemplate, accountService);
119+
warehouseService = new WarehouseService(restTemplate, hostname, port);
114120
}
115121

116122
private RestTemplate createRestTemplate(String login, String password, String hostname, HttpClientBuilder builder,
@@ -227,4 +233,15 @@ public ReportService getReportService() {
227233
return reportService;
228234
}
229235

236+
public ProcessService getProcessService() {
237+
return processService;
238+
}
239+
/**
240+
* Get initialized service for ADS management (create, access and delete ads instances).
241+
*
242+
* @return initialized service for ADS management
243+
*/
244+
public WarehouseService getWarehouseService() {
245+
return warehouseService;
246+
}
230247
}

src/main/java/com/gooddata/PollHandler.java

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,43 @@
1313
/**
1414
* For internal usage by services employing polling.<p>
1515
* Implementing classes should override {@link #isFinished(ClientHttpResponse)} method and
16-
* may override {@link #onFinish()} method.
16+
* may override {@link #onFinish()} and {@link #handlePollResult(Object)} methods.
1717
*
18-
* @see FutureResult
18+
* @param <P> polling type
19+
* @param <R> result type
20+
*
21+
* @see com.gooddata.FutureResult
1922
*/
20-
public class PollHandler<T> {
23+
public class PollHandler<P,R> {
2124

2225
private final String pollingUri;
2326

24-
private final Class<T> resultClass;
27+
private final Class<P> pollClass;
28+
private final Class<R> resultClass;
2529

2630
private boolean done = false;
2731

28-
private T result;
32+
private R result;
2933

3034
/**
3135
* Creates a new instance of polling handler
32-
*
33-
* @param pollingUri URI for polling
34-
* @param resultClass class of the result (or {@link Void})
36+
* @param pollingUri URI for polling
37+
* @param pollAndResultClass class of the polling object and result (or {@link Void})
3538
*/
36-
public PollHandler(final String pollingUri, final Class<T> resultClass) {
39+
@SuppressWarnings("unchecked")
40+
public PollHandler(final String pollingUri, final Class pollAndResultClass) {
41+
this(pollingUri, pollAndResultClass, pollAndResultClass);
42+
}
43+
44+
/**
45+
* Creates a new instance of polling handler
46+
* @param pollingUri URI for polling
47+
* @param pollClass class of the polling object (or {@link Void})
48+
* @param resultClass class of the result (or {@link Void})
49+
*/
50+
public PollHandler(final String pollingUri, final Class<P> pollClass, Class<R> resultClass) {
3751
this.pollingUri = notNull(pollingUri, "pollingUri");
52+
this.pollClass = notNull(pollClass, "pollClass");
3853
this.resultClass = notNull(resultClass, "resultClass");
3954
}
4055

@@ -47,11 +62,15 @@ final String getPollingUri() {
4762
return pollingUri;
4863
}
4964

50-
final Class<T> getResultClass() {
65+
final Class<R> getResultClass() {
5166
return resultClass;
5267
}
5368

54-
final PollHandler<T> setResult(T result) {
69+
final Class<P> getPollClass() {
70+
return pollClass;
71+
}
72+
73+
protected PollHandler<P,R> setResult(R result) {
5574
this.result = result;
5675
this.done = true;
5776
onFinish();
@@ -67,7 +86,7 @@ final boolean isDone() {
6786
*
6887
* @return result
6988
*/
70-
protected final T getResult() {
89+
protected final R getResult() {
7190
return result;
7291
}
7392

@@ -87,4 +106,12 @@ protected boolean isFinished(final ClientHttpResponse response) throws IOExcepti
87106
*/
88107
protected void onFinish() {
89108
}
109+
110+
protected void handlePollResult(P pollResult) {
111+
if (resultClass.equals(pollClass)) {
112+
setResult(resultClass.cast(pollResult));
113+
} else {
114+
throw new IllegalStateException("Please override handlePollResult method when you want different type of polling and result class");
115+
}
116+
}
90117
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.gooddata;
2+
3+
import static com.gooddata.Validate.notNull;
4+
5+
import org.springframework.util.StreamUtils;
6+
7+
import java.io.File;
8+
import java.io.FileInputStream;
9+
import java.io.IOException;
10+
import java.io.OutputStream;
11+
import java.nio.file.Path;
12+
import java.util.zip.ZipEntry;
13+
import java.util.zip.ZipOutputStream;
14+
15+
/**
16+
* Utility class for manipulating zip archives.
17+
*/
18+
public abstract class ZipUtils {
19+
20+
/**
21+
* This method compresses the input file to zip format. If the given file is a directory, it recursively
22+
* packs the directory into the output. Not including give directory itself
23+
*
24+
* @param file file to be zipped
25+
* @param output stream where the output will be written
26+
*/
27+
public static void zip(File file, OutputStream output) throws IOException {
28+
zip(file, output, false);
29+
}
30+
31+
/**
32+
* This method compresses the input file to zip format. If the given file is a directory, it recursively
33+
* packs the directory into the output.
34+
*
35+
* @param file file to be zipped
36+
* @param output stream where the output will be written
37+
* @param includeRoot if root dir should be included
38+
*/
39+
public static void zip(File file, OutputStream output, boolean includeRoot) throws IOException {
40+
notNull(file, "file");
41+
notNull(output, "output");
42+
43+
try (ZipOutputStream zos = new ZipOutputStream(output)) {
44+
if (file.isDirectory()) {
45+
zipDir(includeRoot ? file.getParentFile().toPath() : file.toPath(), file, zos);
46+
} else {
47+
zipFile(file.getParentFile().toPath(), file, zos);
48+
}
49+
50+
}
51+
}
52+
53+
private static void zipDir(Path rootPath, File dir, ZipOutputStream zos) throws IOException {
54+
for (File file : notNull(dir.listFiles(), "listed files")) {
55+
if (file.isDirectory()) {
56+
zipDir(rootPath, file, zos);
57+
} else {
58+
zipFile(rootPath, file, zos);
59+
}
60+
}
61+
}
62+
63+
private static void zipFile(Path rootPath, File file, ZipOutputStream zos) throws IOException {
64+
ZipEntry ze = new ZipEntry(rootPath.relativize(file.toPath()).toString());
65+
zos.putNextEntry(ze);
66+
try (FileInputStream fis = new FileInputStream(file)) {
67+
StreamUtils.copy(fis, zos);
68+
}
69+
zos.closeEntry();
70+
}
71+
}

0 commit comments

Comments
 (0)