PageRenderTime 56ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/src/main/java/com/treasuredata/client/TDClient.java

https://gitlab.com/github-cloud-corp/td-client-java
Java | 840 lines | 704 code | 101 blank | 35 comment | 37 complexity | b6a4a3b1ea71dc7db3a5f7f373808310 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing,
  13. * software distributed under the License is distributed on an
  14. * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15. * KIND, either express or implied. See the License for the
  16. * specific language governing permissions and limitations
  17. * under the License.
  18. */
  19. package com.treasuredata.client;
  20. import com.fasterxml.jackson.core.JsonProcessingException;
  21. import com.fasterxml.jackson.databind.node.ObjectNode;
  22. import com.google.common.annotations.VisibleForTesting;
  23. import com.google.common.base.Function;
  24. import com.google.common.base.Optional;
  25. import com.google.common.base.Throwables;
  26. import com.google.common.collect.ImmutableList;
  27. import com.google.common.collect.ImmutableMap;
  28. import com.treasuredata.client.model.ObjectMappers;
  29. import com.treasuredata.client.model.TDAuthenticationResult;
  30. import com.treasuredata.client.model.TDBulkImportParts;
  31. import com.treasuredata.client.model.TDBulkImportSession;
  32. import com.treasuredata.client.model.TDBulkImportSessionList;
  33. import com.treasuredata.client.model.TDBulkLoadSessionStartRequest;
  34. import com.treasuredata.client.model.TDBulkLoadSessionStartResult;
  35. import com.treasuredata.client.model.TDColumn;
  36. import com.treasuredata.client.model.TDDatabase;
  37. import com.treasuredata.client.model.TDExportJobRequest;
  38. import com.treasuredata.client.model.TDJob;
  39. import com.treasuredata.client.model.TDJobList;
  40. import com.treasuredata.client.model.TDJobRequest;
  41. import com.treasuredata.client.model.TDJobSubmitResult;
  42. import com.treasuredata.client.model.TDJobSummary;
  43. import com.treasuredata.client.model.TDPartialDeleteJob;
  44. import com.treasuredata.client.model.TDResultFormat;
  45. import com.treasuredata.client.model.TDSaveQueryRequest;
  46. import com.treasuredata.client.model.TDSavedQuery;
  47. import com.treasuredata.client.model.TDSavedQueryHistory;
  48. import com.treasuredata.client.model.TDSavedQueryStartRequest;
  49. import com.treasuredata.client.model.TDSavedQueryUpdateRequest;
  50. import com.treasuredata.client.model.TDTable;
  51. import com.treasuredata.client.model.TDTableList;
  52. import com.treasuredata.client.model.TDTableType;
  53. import com.treasuredata.client.model.TDUpdateTableResult;
  54. import com.treasuredata.client.model.TDUser;
  55. import com.treasuredata.client.model.TDUserList;
  56. import com.treasuredata.client.model.impl.TDDatabaseList;
  57. import com.treasuredata.client.model.impl.TDScheduleRunResult;
  58. import org.eclipse.jetty.http.HttpStatus;
  59. import org.json.simple.JSONObject;
  60. import org.slf4j.Logger;
  61. import org.slf4j.LoggerFactory;
  62. import java.io.File;
  63. import java.io.InputStream;
  64. import java.net.URL;
  65. import java.util.ArrayList;
  66. import java.util.Date;
  67. import java.util.HashMap;
  68. import java.util.List;
  69. import java.util.Map;
  70. import java.util.Properties;
  71. import java.util.regex.Pattern;
  72. import static com.google.common.base.Preconditions.checkNotNull;
  73. import static com.google.common.net.UrlEscapers.urlPathSegmentEscaper;
  74. /**
  75. *
  76. */
  77. public class TDClient
  78. implements TDClientApi<TDClient>
  79. {
  80. private static final Logger logger = LoggerFactory.getLogger(TDClient.class);
  81. private static final String version;
  82. public static String getVersion()
  83. {
  84. return version;
  85. }
  86. static String readMavenVersion(URL mavenProperties)
  87. {
  88. String v = "unknown";
  89. if (mavenProperties != null) {
  90. try (InputStream in = mavenProperties.openStream()) {
  91. Properties p = new Properties();
  92. p.load(in);
  93. v = p.getProperty("version", "unknown");
  94. }
  95. catch (Throwable e) {
  96. logger.warn("Error in reading pom.properties file", e);
  97. }
  98. }
  99. return v;
  100. }
  101. static {
  102. URL mavenProperties = TDClient.class.getResource("/META-INF/maven/com.treasuredata.client/td-client/pom.properties");
  103. version = readMavenVersion(mavenProperties);
  104. logger.info("td-client version: " + version);
  105. }
  106. public static TDClient newClient()
  107. {
  108. return new TDClientBuilder(true).build();
  109. }
  110. public static TDClientBuilder newBuilder()
  111. {
  112. return new TDClientBuilder(true);
  113. }
  114. public static TDClientBuilder newBuilder(boolean loadTDConf)
  115. {
  116. return new TDClientBuilder(loadTDConf);
  117. }
  118. /**
  119. * Create a new TDClient that uses the given api key for the authentication.
  120. * The new instance of TDClient shares the same HttpClient, so closing this will invalidate the other copy of TDClient instances
  121. *
  122. * @param newApiKey
  123. * @return
  124. */
  125. @Override
  126. public TDClient withApiKey(String newApiKey)
  127. {
  128. return new TDClient(config, httpClient, Optional.of(newApiKey));
  129. }
  130. @VisibleForTesting
  131. protected final TDClientConfig config;
  132. @VisibleForTesting
  133. protected final TDHttpClient httpClient;
  134. protected final Optional<String> apiKeyCache;
  135. public TDClient(TDClientConfig config)
  136. {
  137. this(config, new TDHttpClient(config), config.apiKey);
  138. }
  139. protected TDClient(TDClientConfig config, TDHttpClient httpClient, Optional<String> apiKeyCache)
  140. {
  141. this.config = config;
  142. this.httpClient = httpClient;
  143. this.apiKeyCache = apiKeyCache;
  144. }
  145. public void close()
  146. {
  147. httpClient.close();
  148. }
  149. protected static String buildUrl(String urlPrefix, String... args)
  150. {
  151. StringBuilder s = new StringBuilder();
  152. s.append(urlPrefix);
  153. for (String a : args) {
  154. s.append("/");
  155. s.append(urlPathSegmentEscaper().escape(a));
  156. }
  157. return s.toString();
  158. }
  159. protected <ResultType> ResultType doGet(String path, Class<ResultType> resultTypeClass)
  160. throws TDClientException
  161. {
  162. checkNotNull(path, "path is null");
  163. checkNotNull(resultTypeClass, "resultTypeClass is null");
  164. TDApiRequest request = TDApiRequest.Builder.GET(path).build();
  165. return httpClient.call(request, apiKeyCache, resultTypeClass);
  166. }
  167. protected <ResultType> ResultType doPost(String path, Map<String, String> queryParam, Optional<String> jsonBody, Class<ResultType> resultTypeClass)
  168. throws TDClientException
  169. {
  170. checkNotNull(path, "path is null");
  171. checkNotNull(queryParam, "param is null");
  172. checkNotNull(jsonBody, "body is null");
  173. checkNotNull(resultTypeClass, "resultTypeClass is null");
  174. TDApiRequest.Builder request = TDApiRequest.Builder.POST(path);
  175. for (Map.Entry<String, String> e : queryParam.entrySet()) {
  176. request.addQueryParam(e.getKey(), e.getValue());
  177. }
  178. if (jsonBody.isPresent()) {
  179. request.setPostJson(jsonBody.get());
  180. }
  181. return httpClient.call(request.build(), apiKeyCache, resultTypeClass);
  182. }
  183. protected <ResultType> ResultType doPost(String path, Class<ResultType> resultTypeClass)
  184. throws TDClientException
  185. {
  186. return this.<ResultType>doPost(path, ImmutableMap.<String, String>of(), Optional.<String>absent(), resultTypeClass);
  187. }
  188. protected <ResultType> ResultType doPost(String path, Map<String, String> queryParam, Class<ResultType> resultTypeClass)
  189. throws TDClientException
  190. {
  191. return this.<ResultType>doPost(path, queryParam, Optional.<String>absent(), resultTypeClass);
  192. }
  193. protected String doPost(String path)
  194. throws TDClientException
  195. {
  196. checkNotNull(path, "path is null");
  197. TDApiRequest request = TDApiRequest.Builder.POST(path).build();
  198. return httpClient.call(request, apiKeyCache);
  199. }
  200. protected String doPut(String path, File filePath)
  201. throws TDClientException
  202. {
  203. checkNotNull(path, "path is null");
  204. checkNotNull(filePath, "filePath is null");
  205. TDApiRequest request = TDApiRequest.Builder.PUT(path).setFile(filePath).build();
  206. return httpClient.call(request, apiKeyCache);
  207. }
  208. @Override
  209. public TDClient authenticate(String email, String password)
  210. {
  211. TDAuthenticationResult authResult = doPost("/v3/user/authenticate", ImmutableMap.of("user", email, "password", password), TDAuthenticationResult.class);
  212. return withApiKey(authResult.getApikey());
  213. }
  214. @Override
  215. public TDUser getUser()
  216. {
  217. return doGet("/v3/user/show", TDUser.class);
  218. }
  219. @Override
  220. public TDUserList listUsers()
  221. {
  222. return doGet("/v3/user/list", TDUserList.class);
  223. }
  224. @Override
  225. public String serverStatus()
  226. {
  227. // No API key is requried for server_status
  228. return httpClient.call(TDApiRequest.Builder.GET("/v3/system/server_status").build(), Optional.<String>absent());
  229. }
  230. @Override
  231. public List<String> listDatabaseNames()
  232. throws TDClientException
  233. {
  234. ArrayList<String> tableList = new ArrayList<>();
  235. for (TDDatabase db : listDatabases()) {
  236. tableList.add(db.getName());
  237. }
  238. return tableList;
  239. }
  240. @Override
  241. public List<TDDatabase> listDatabases()
  242. throws TDClientException
  243. {
  244. TDDatabaseList result = doGet("/v3/database/list", TDDatabaseList.class);
  245. return result.getDatabases();
  246. }
  247. private static Pattern acceptableNamePattern = Pattern.compile("^([a-z0-9_]+)$");
  248. static String validateDatabaseName(String databaseName)
  249. {
  250. return validateName(databaseName, "Database");
  251. }
  252. static String validateTableName(String tableName)
  253. {
  254. return validateName(tableName, "Table");
  255. }
  256. private static String validateName(String name, String type)
  257. {
  258. // Validate database name
  259. if (name.length() < 3 || name.length() > 256) {
  260. throw new TDClientException(
  261. TDClientException.ErrorType.INVALID_INPUT, String.format(
  262. "%s name must be 3 to 256 characters but got %d characters: %s", type, name.length(), name));
  263. }
  264. if (!acceptableNamePattern.matcher(name).matches()) {
  265. throw new TDClientException(TDClientException.ErrorType.INVALID_INPUT,
  266. String.format("%s name must follow this pattern %s: %s", type, acceptableNamePattern.pattern(), name));
  267. }
  268. return name;
  269. }
  270. @Override
  271. public void createDatabase(String databaseName)
  272. throws TDClientException
  273. {
  274. doPost(buildUrl("/v3/database/create", validateDatabaseName(databaseName)));
  275. }
  276. @Override
  277. public void createDatabaseIfNotExists(String databaseName)
  278. throws TDClientException
  279. {
  280. try {
  281. createDatabase(databaseName);
  282. }
  283. catch (TDClientHttpConflictException e) {
  284. // This can be thrown when the database already exists or Nginx returns conflict(409) upon request retry
  285. }
  286. }
  287. @Override
  288. public void deleteDatabase(String databaseName)
  289. throws TDClientException
  290. {
  291. doPost(buildUrl("/v3/database/delete", validateDatabaseName(databaseName)));
  292. }
  293. @Override
  294. public void deleteDatabaseIfExists(String databaseName)
  295. throws TDClientException
  296. {
  297. try {
  298. deleteDatabase(databaseName);
  299. }
  300. catch (TDClientHttpNotFoundException e) {
  301. // This will be thrown when the database does not exist, or Nginx calls this delete request twice
  302. }
  303. }
  304. @Override
  305. public List<TDTable> listTables(String databaseName)
  306. throws TDClientException
  307. {
  308. TDTableList tableList = doGet(buildUrl("/v3/table/list", databaseName), TDTableList.class);
  309. return tableList.getTables();
  310. }
  311. @Override
  312. public boolean existsDatabase(String databaseName)
  313. throws TDClientException
  314. {
  315. return listDatabaseNames().contains(databaseName);
  316. }
  317. @Override
  318. public boolean existsTable(String databaseName, String tableName)
  319. throws TDClientException
  320. {
  321. try {
  322. for (TDTable table : listTables(databaseName)) {
  323. if (table.getName().equals(tableName)) {
  324. return true;
  325. }
  326. }
  327. return false;
  328. }
  329. catch (TDClientHttpException e) {
  330. if (e.getStatusCode() == HttpStatus.NOT_FOUND_404) {
  331. return false;
  332. }
  333. else {
  334. throw e;
  335. }
  336. }
  337. }
  338. @Override
  339. public void createTable(String databaseName, String tableName)
  340. throws TDClientException
  341. {
  342. doPost(buildUrl("/v3/table/create", databaseName, validateTableName(tableName), TDTableType.LOG.getTypeName()));
  343. }
  344. @Override
  345. public void createTableIfNotExists(String databaseName, String tableName)
  346. throws TDClientException
  347. {
  348. try {
  349. createTable(databaseName, tableName);
  350. }
  351. catch (TDClientHttpConflictException e) {
  352. // This can be thrown when the table already exists or Nginx returns conflict(409) upon request retry
  353. }
  354. }
  355. @Override
  356. public void renameTable(String databaseName, String tableName, String newTableName)
  357. throws TDClientException
  358. {
  359. renameTable(databaseName, tableName, newTableName, false);
  360. }
  361. @Override
  362. public void renameTable(String databaseName, String tableName, String newTableName, boolean overwrite)
  363. throws TDClientException
  364. {
  365. doPost(buildUrl("/v3/table/rename", databaseName, tableName, validateTableName(newTableName)),
  366. ImmutableMap.of("overwrite", Boolean.toString(overwrite)),
  367. TDUpdateTableResult.class
  368. );
  369. }
  370. @Override
  371. public void deleteTable(String databaseName, String tableName)
  372. throws TDClientException
  373. {
  374. doPost(buildUrl("/v3/table/delete", databaseName, tableName));
  375. }
  376. @Override
  377. public void deleteTableIfExists(String databaseName, String tableName)
  378. throws TDClientException
  379. {
  380. try {
  381. deleteTable(databaseName, tableName);
  382. }
  383. catch (TDClientHttpNotFoundException e) {
  384. // This will be thrown the table does not exists or Nginx calls this API request twice
  385. }
  386. }
  387. @Override
  388. public TDPartialDeleteJob partialDelete(String databaseName, String tableName, long from, long to)
  389. throws TDClientException
  390. {
  391. if ((from % 3600 != 0) || (to % 3600 != 0)) {
  392. throw new TDClientException(TDClientException.ErrorType.INVALID_INPUT, String.format("from/to value must be a multiple of 3600: [%s, %s)", from, to));
  393. }
  394. Map<String, String> queryParams = ImmutableMap.of(
  395. "from", Long.toString(from),
  396. "to", Long.toString(to));
  397. TDPartialDeleteJob job = doPost(buildUrl("/v3/table/partialdelete", databaseName, tableName), queryParams, TDPartialDeleteJob.class);
  398. return job;
  399. }
  400. @Override
  401. public void swapTables(String databaseName, String tableName1, String tableName2)
  402. {
  403. doPost(buildUrl("/v3/table/swap", databaseName, tableName1, tableName2));
  404. }
  405. private TDTable getTable(String databaseName, String tableName)
  406. {
  407. checkNotNull(databaseName, "databaseName is null");
  408. checkNotNull(tableName, "tableName is null");
  409. // TODO This should be improved via v4 api
  410. for (TDTable table : listTables(databaseName)) {
  411. if (table.getName().equals(tableName)) {
  412. return table;
  413. }
  414. }
  415. throw new TDClientException(TDClientException.ErrorType.TARGET_NOT_FOUND, String.format("Table %s is not found", tableName));
  416. }
  417. @Override
  418. public void updateTableSchema(String databaseName, String tableName, List<TDColumn> newSchema)
  419. {
  420. checkNotNull(databaseName, "databaseName is null");
  421. checkNotNull(tableName, "tableName is null");
  422. checkNotNull(newSchema, "newSchema is null");
  423. ImmutableList.Builder<List<String>> builder = ImmutableList.<List<String>>builder();
  424. for (TDColumn newColumn : newSchema) {
  425. builder.add(ImmutableList.of(newColumn.getKeyString(), newColumn.getType().toString(), newColumn.getName()));
  426. }
  427. String schemaJson = JSONObject.toJSONString(ImmutableMap.of("schema", builder.build()));
  428. doPost(buildUrl("/v3/table/update-schema", databaseName, tableName), ImmutableMap.<String, String>of(), Optional.of(schemaJson), String.class);
  429. }
  430. @Override
  431. public String submit(TDJobRequest jobRequest)
  432. throws TDClientException
  433. {
  434. Map<String, String> queryParam = new HashMap<>();
  435. queryParam.put("query", jobRequest.getQuery());
  436. queryParam.put("version", getVersion());
  437. if (jobRequest.getResultOutput().isPresent()) {
  438. queryParam.put("result", jobRequest.getResultOutput().get());
  439. }
  440. queryParam.put("priority", Integer.toString(jobRequest.getPriority().toInt()));
  441. if (jobRequest.getRetryLimit().isPresent()) {
  442. queryParam.put("retry_limit", Integer.toString(jobRequest.getRetryLimit().get()));
  443. }
  444. if (jobRequest.getPoolName().isPresent()) {
  445. queryParam.put("pool_name", jobRequest.getPoolName().get());
  446. }
  447. if (jobRequest.getTable().isPresent()) {
  448. queryParam.put("table", jobRequest.getTable().get());
  449. }
  450. if (jobRequest.getScheduledTime().isPresent()) {
  451. queryParam.put("scheduled_time", String.valueOf(jobRequest.getScheduledTime().get()));
  452. }
  453. if (jobRequest.getDomainKey().isPresent()) {
  454. queryParam.put("domain_key", jobRequest.getDomainKey().get());
  455. }
  456. if (logger.isDebugEnabled()) {
  457. logger.debug("submit job: " + jobRequest);
  458. }
  459. TDJobSubmitResult result =
  460. doPost(
  461. buildUrl("/v3/job/issue", jobRequest.getType().getType(), jobRequest.getDatabase()),
  462. queryParam,
  463. jobRequest.getConfig().transform(new Function<ObjectNode, String>()
  464. {
  465. public String apply(ObjectNode config)
  466. {
  467. ObjectNode body = config.objectNode();
  468. body.set("config", config);
  469. return body.toString();
  470. }
  471. }),
  472. TDJobSubmitResult.class);
  473. return result.getJobId();
  474. }
  475. @Override
  476. public TDJobList listJobs()
  477. throws TDClientException
  478. {
  479. return doGet("/v3/job/list", TDJobList.class);
  480. }
  481. @Override
  482. public TDJobList listJobs(long fromJobId, long toJobId)
  483. throws TDClientException
  484. {
  485. return doGet(String.format("/v3/job/list?from_id=%d&to_id=%d", fromJobId, toJobId), TDJobList.class);
  486. }
  487. @Override
  488. public void killJob(String jobId)
  489. throws TDClientException
  490. {
  491. doPost(buildUrl("/v3/job/kill", jobId));
  492. }
  493. @Override
  494. public TDJobSummary jobStatus(String jobId)
  495. throws TDClientException
  496. {
  497. return doGet(buildUrl("/v3/job/status", jobId), TDJobSummary.class);
  498. }
  499. @Override
  500. public TDJobSummary jobStatusByDomainKey(String domainKey)
  501. {
  502. return doGet(buildUrl("/v3/job/status_by_domain_key", domainKey), TDJobSummary.class);
  503. }
  504. @Override
  505. public TDJob jobInfo(String jobId)
  506. throws TDClientException
  507. {
  508. return doGet(buildUrl("/v3/job/show", jobId), TDJob.class);
  509. }
  510. @Override
  511. public <Result> Result jobResult(String jobId, TDResultFormat format, Function<InputStream, Result> resultStreamHandler)
  512. throws TDClientException
  513. {
  514. TDApiRequest request = TDApiRequest.Builder
  515. .GET(buildUrl("/v3/job/result", jobId))
  516. .addQueryParam("format", format.getName())
  517. .build();
  518. return httpClient.<Result>call(request, apiKeyCache, resultStreamHandler);
  519. }
  520. @Override
  521. public List<TDBulkImportSession> listBulkImportSessions()
  522. {
  523. return doGet(buildUrl("/v3/bulk_import/list"), TDBulkImportSessionList.class).getSessions();
  524. }
  525. @Override
  526. public List<String> listBulkImportParts(String sessionName)
  527. {
  528. return doGet(buildUrl("/v3/bulk_import/list_parts", sessionName), TDBulkImportParts.class).getParts();
  529. }
  530. @Override
  531. public void createBulkImportSession(String sessionName, String databaseName, String tableName)
  532. {
  533. doPost(buildUrl("/v3/bulk_import/create", sessionName, databaseName, tableName));
  534. }
  535. @Override
  536. public TDBulkImportSession getBulkImportSession(String sessionName)
  537. {
  538. return doGet(buildUrl("/v3/bulk_import/show", sessionName), TDBulkImportSession.class);
  539. }
  540. @Override
  541. public void uploadBulkImportPart(String sessionName, String uniquePartName, File path)
  542. {
  543. doPut(buildUrl("/v3/bulk_import/upload_part", sessionName, uniquePartName), path);
  544. }
  545. public void deleteBulkImportPart(String sessionName, String uniquePartName)
  546. {
  547. doPost(buildUrl("/v3/bulk_import/delete_part", sessionName, uniquePartName));
  548. }
  549. @Override
  550. public void freezeBulkImportSession(String sessionName)
  551. {
  552. doPost(buildUrl("/v3/bulk_import/freeze", sessionName));
  553. }
  554. @Override
  555. public void unfreezeBulkImportSession(String sessionName)
  556. {
  557. doPost(buildUrl("/v3/bulk_import/unfreeze", sessionName));
  558. }
  559. @Override
  560. public void performBulkImportSession(String sessionName)
  561. {
  562. performBulkImportSession(sessionName, TDJob.Priority.NORMAL);
  563. }
  564. @Override
  565. public void performBulkImportSession(String sessionName, TDJob.Priority priority)
  566. {
  567. doPost(buildUrl("/v3/bulk_import/perform", sessionName), ImmutableMap.of("priority", Integer.toString(priority.toInt())), Optional.<String>absent(), String.class);
  568. }
  569. @Override
  570. public void commitBulkImportSession(String sessionName)
  571. {
  572. doPost(buildUrl("/v3/bulk_import/commit", sessionName));
  573. }
  574. @Override
  575. public void deleteBulkImportSession(String sessionName)
  576. {
  577. doPost(buildUrl("/v3/bulk_import/delete", sessionName));
  578. }
  579. @Override
  580. public <Result> Result getBulkImportErrorRecords(String sessionName, Function<InputStream, Result> resultStreamHandler)
  581. {
  582. TDApiRequest request = TDApiRequest.Builder
  583. .GET(buildUrl("/v3/bulk_import/error_records", sessionName))
  584. .build();
  585. return httpClient.<Result>call(request, apiKeyCache, resultStreamHandler);
  586. }
  587. @Override
  588. public String startSavedQuery(String name, Date scheduledTime)
  589. {
  590. return startSavedQuery(TDSavedQueryStartRequest.builder()
  591. .name(name)
  592. .scheduledTime(scheduledTime)
  593. .build());
  594. }
  595. @Override
  596. public String startSavedQuery(TDSavedQueryStartRequest request)
  597. {
  598. Map<String, String> queryParams = new HashMap<>();
  599. Optional<Integer> num = request.num();
  600. if (num.isPresent()) {
  601. queryParams.put("num", Integer.toString(num.get()));
  602. }
  603. Optional<String> domainKey = request.domainKey();
  604. if (domainKey.isPresent()) {
  605. queryParams.put("domain_key", domainKey.get());
  606. }
  607. TDScheduleRunResult result =
  608. doPost(buildUrl("/v3/schedule/run", request.name(), Long.toString(request.scheduledTime().getTime() / 1000)),
  609. queryParams,
  610. TDScheduleRunResult.class);
  611. return result.getJobs().get(0).getJobId();
  612. }
  613. @Override
  614. public List<TDSavedQuery> listSavedQueries()
  615. {
  616. return doGet(buildUrl("/v3/schedule/list"), TDSavedQuery.TDSavedQueryList.class).getSchedules();
  617. }
  618. @Override
  619. public TDSavedQueryHistory getSavedQueryHistory(String name)
  620. {
  621. return getSavedQueryHistory(name, 0L, 20L);
  622. }
  623. @Override
  624. public TDSavedQueryHistory getSavedQueryHistory(String name, Long from, Long to)
  625. {
  626. TDApiRequest.Builder builder = TDApiRequest.Builder
  627. .GET(buildUrl("/v3/schedule/history", name));
  628. if (from != null) {
  629. builder.addQueryParam("from", String.valueOf(from));
  630. }
  631. if (to != null) {
  632. builder.addQueryParam("to", String.valueOf(to));
  633. }
  634. TDApiRequest request = builder.build();
  635. return httpClient.call(request, apiKeyCache, TDSavedQueryHistory.class);
  636. }
  637. protected String toJson(Object any)
  638. {
  639. try {
  640. return httpClient.getObjectMapper().writeValueAsString(any);
  641. }
  642. catch (JsonProcessingException e) {
  643. logger.error("Failed to produce json", e);
  644. throw new TDClientException(TDClientException.ErrorType.INVALID_INPUT, String.format("Failed to create JSON string from %s", any));
  645. }
  646. }
  647. @Override
  648. public TDSavedQuery saveQuery(TDSaveQueryRequest request)
  649. {
  650. String json = toJson(request);
  651. TDSavedQuery result =
  652. doPost(
  653. buildUrl("/v3/schedule/create", request.getName()),
  654. ImmutableMap.<String, String>of(),
  655. Optional.of(json),
  656. TDSavedQuery.class);
  657. return result;
  658. }
  659. @Override
  660. public TDSavedQuery updateSavedQuery(String name, TDSavedQueryUpdateRequest request)
  661. {
  662. String json = request.toJson();
  663. TDSavedQuery result =
  664. doPost(
  665. buildUrl("/v3/schedule/update", name),
  666. ImmutableMap.<String, String>of(),
  667. Optional.of(json),
  668. TDSavedQuery.class);
  669. return result;
  670. }
  671. @Override
  672. public TDSavedQuery deleteSavedQuery(String name)
  673. {
  674. TDSavedQuery result = doPost(
  675. buildUrl("/v3/schedule/delete", name),
  676. TDSavedQuery.class);
  677. return result;
  678. }
  679. @Override
  680. public String submitExportJob(TDExportJobRequest jobRequest)
  681. throws TDClientException
  682. {
  683. Map<String, String> queryParam = new HashMap<>();
  684. queryParam.put("from", Long.toString(jobRequest.getFrom().getTime() / 1000));
  685. queryParam.put("to", Long.toString(jobRequest.getTo().getTime() / 1000));
  686. queryParam.put("file_prefix", jobRequest.getFilePrefix());
  687. queryParam.put("file_format", jobRequest.getFileFormat().toString());
  688. queryParam.put("storage_type", "s3");
  689. queryParam.put("bucket", jobRequest.getBucketName());
  690. queryParam.put("access_key_id", jobRequest.getAccessKeyId());
  691. queryParam.put("secret_access_key", jobRequest.getSecretAccessKey());
  692. if (jobRequest.getPoolName().isPresent()) {
  693. queryParam.put("pool_name", jobRequest.getPoolName().get());
  694. }
  695. Optional<String> domainKey = jobRequest.getDomainKey();
  696. if (domainKey.isPresent()) {
  697. queryParam.put("domain_key", domainKey.get());
  698. }
  699. if (logger.isDebugEnabled()) {
  700. logger.debug("submit job: " + jobRequest);
  701. }
  702. TDJobSubmitResult result =
  703. doPost(
  704. buildUrl("/v3/export/run", jobRequest.getDatabase(), jobRequest.getTable()),
  705. queryParam,
  706. TDJobSubmitResult.class);
  707. return result.getJobId();
  708. }
  709. @Override
  710. public TDBulkLoadSessionStartResult startBulkLoadSession(String name)
  711. {
  712. TDBulkLoadSessionStartRequest request = TDBulkLoadSessionStartRequest.builder()
  713. .build();
  714. return startBulkLoadSession(name, request);
  715. }
  716. @Override
  717. public TDBulkLoadSessionStartResult startBulkLoadSession(String name, long scheduledTime)
  718. {
  719. TDBulkLoadSessionStartRequest request = TDBulkLoadSessionStartRequest.builder()
  720. .setScheduledTime(String.valueOf(scheduledTime))
  721. .build();
  722. return startBulkLoadSession(name, request);
  723. }
  724. @Override
  725. public TDBulkLoadSessionStartResult startBulkLoadSession(String name, TDBulkLoadSessionStartRequest request)
  726. {
  727. Map<String, String> queryParams = ImmutableMap.of();
  728. String payload = null;
  729. try {
  730. payload = ObjectMappers.compactMapper().writeValueAsString(request);
  731. }
  732. catch (JsonProcessingException e) {
  733. throw Throwables.propagate(e);
  734. }
  735. return doPost(buildUrl("/v3/bulk_loads", name, "jobs"),
  736. queryParams, Optional.of(payload),
  737. TDBulkLoadSessionStartResult.class);
  738. }
  739. }