001/** 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.oozie.client; 019 020import org.apache.oozie.BuildInfo; 021import org.apache.oozie.client.rest.JsonTags; 022import org.apache.oozie.client.rest.JsonToBean; 023import org.apache.oozie.client.rest.RestConstants; 024import org.apache.oozie.client.retry.ConnectionRetriableClient; 025import org.json.simple.JSONArray; 026import org.json.simple.JSONObject; 027import org.json.simple.JSONValue; 028import org.w3c.dom.Document; 029import org.w3c.dom.Element; 030 031import javax.xml.parsers.DocumentBuilderFactory; 032import javax.xml.transform.Transformer; 033import javax.xml.transform.TransformerFactory; 034import javax.xml.transform.dom.DOMSource; 035import javax.xml.transform.stream.StreamResult; 036import java.io.BufferedReader; 037import java.io.IOException; 038import java.io.InputStream; 039import java.io.InputStreamReader; 040import java.io.OutputStream; 041import java.io.PrintStream; 042import java.io.Reader; 043import java.net.HttpURLConnection; 044import java.net.URL; 045import java.net.URLEncoder; 046import java.util.ArrayList; 047import java.util.Collections; 048import java.util.HashMap; 049import java.util.Iterator; 050import java.util.LinkedHashMap; 051import java.util.List; 052import java.util.Map; 053import java.util.Properties; 054import java.util.concurrent.Callable; 055 056/** 057 * Client API to submit and manage Oozie workflow jobs against an Oozie intance. 058 * <p/> 059 * This class is thread safe. 060 * <p/> 061 * Syntax for filter for the {@link #getJobsInfo(String)} {@link #getJobsInfo(String, int, int)} methods: 062 * <code>[NAME=VALUE][;NAME=VALUE]*</code>. 063 * <p/> 064 * Valid filter names are: 065 * <p/> 066 * <ul/> 067 * <li>name: the workflow application name from the workflow definition.</li> 068 * <li>user: the user that submitted the job.</li> 069 * <li>group: the group for the job.</li> 070 * <li>status: the status of the job.</li> 071 * </ul> 072 * <p/> 073 * The query will do an AND among all the filter names. The query will do an OR among all the filter values for the same 074 * name. Multiple values must be specified as different name value pairs. 075 */ 076public class OozieClient { 077 078 public static final long WS_PROTOCOL_VERSION_0 = 0; 079 080 public static final long WS_PROTOCOL_VERSION_1 = 1; 081 082 public static final long WS_PROTOCOL_VERSION = 2; // pointer to current version 083 084 public static final String USER_NAME = "user.name"; 085 086 @Deprecated 087 public static final String GROUP_NAME = "group.name"; 088 089 public static final String JOB_ACL = "oozie.job.acl"; 090 091 public static final String APP_PATH = "oozie.wf.application.path"; 092 093 public static final String COORDINATOR_APP_PATH = "oozie.coord.application.path"; 094 095 public static final String BUNDLE_APP_PATH = "oozie.bundle.application.path"; 096 097 public static final String BUNDLE_ID = "oozie.bundle.id"; 098 099 public static final String EXTERNAL_ID = "oozie.wf.external.id"; 100 101 public static final String WORKFLOW_NOTIFICATION_URL = "oozie.wf.workflow.notification.url"; 102 103 public static final String ACTION_NOTIFICATION_URL = "oozie.wf.action.notification.url"; 104 105 public static final String COORD_ACTION_NOTIFICATION_URL = "oozie.coord.action.notification.url"; 106 107 public static final String RERUN_SKIP_NODES = "oozie.wf.rerun.skip.nodes"; 108 109 public static final String RERUN_FAIL_NODES = "oozie.wf.rerun.failnodes"; 110 111 public static final String LOG_TOKEN = "oozie.wf.log.token"; 112 113 public static final String ACTION_MAX_RETRIES = "oozie.wf.action.max.retries"; 114 115 public static final String ACTION_RETRY_INTERVAL = "oozie.wf.action.retry.interval"; 116 117 public static final String FILTER_USER = "user"; 118 119 public static final String FILTER_GROUP = "group"; 120 121 public static final String FILTER_NAME = "name"; 122 123 public static final String FILTER_STATUS = "status"; 124 125 public static final String FILTER_NOMINAL_TIME = "nominaltime"; 126 127 public static final String FILTER_FREQUENCY = "frequency"; 128 129 public static final String FILTER_ID = "id"; 130 131 public static final String FILTER_UNIT = "unit"; 132 133 public static final String FILTER_JOBID = "jobid"; 134 135 public static final String FILTER_APPNAME = "appname"; 136 137 public static final String FILTER_SLA_APPNAME = "app_name"; 138 139 public static final String FILTER_SLA_ID = "id"; 140 141 public static final String FILTER_SLA_PARENT_ID = "parent_id"; 142 143 public static final String FILTER_SLA_NOMINAL_START = "nominal_start"; 144 145 public static final String FILTER_SLA_NOMINAL_END = "nominal_end"; 146 147 public static final String CHANGE_VALUE_ENDTIME = "endtime"; 148 149 public static final String CHANGE_VALUE_PAUSETIME = "pausetime"; 150 151 public static final String CHANGE_VALUE_CONCURRENCY = "concurrency"; 152 153 public static final String CHANGE_VALUE_STATUS = "status"; 154 155 public static final String LIBPATH = "oozie.libpath"; 156 157 public static final String USE_SYSTEM_LIBPATH = "oozie.use.system.libpath"; 158 159 public static final String OOZIE_SUSPEND_ON_NODES = "oozie.suspend.on.nodes"; 160 161 public static enum SYSTEM_MODE { 162 NORMAL, NOWEBSERVICE, SAFEMODE 163 } 164 165 /** 166 * debugMode =0 means no debugging. > 0 means debugging on. 167 */ 168 public int debugMode = 0; 169 170 private int retryCount = 4; 171 172 173 private String baseUrl; 174 private String protocolUrl; 175 private boolean validatedVersion = false; 176 private JSONArray supportedVersions; 177 private final Map<String, String> headers = new HashMap<String, String>(); 178 179 private static final ThreadLocal<String> USER_NAME_TL = new ThreadLocal<String>(); 180 181 /** 182 * Allows to impersonate other users in the Oozie server. The current user 183 * must be configured as a proxyuser in Oozie. 184 * <p/> 185 * IMPORTANT: impersonation happens only with Oozie client requests done within 186 * doAs() calls. 187 * 188 * @param userName user to impersonate. 189 * @param callable callable with {@link OozieClient} calls impersonating the specified user. 190 * @return any response returned by the {@link Callable#call()} method. 191 * @throws Exception thrown by the {@link Callable#call()} method. 192 */ 193 public static <T> T doAs(String userName, Callable<T> callable) throws Exception { 194 notEmpty(userName, "userName"); 195 notNull(callable, "callable"); 196 try { 197 USER_NAME_TL.set(userName); 198 return callable.call(); 199 } 200 finally { 201 USER_NAME_TL.remove(); 202 } 203 } 204 205 protected OozieClient() { 206 } 207 208 /** 209 * Create a Workflow client instance. 210 * 211 * @param oozieUrl URL of the Oozie instance it will interact with. 212 */ 213 public OozieClient(String oozieUrl) { 214 this.baseUrl = notEmpty(oozieUrl, "oozieUrl"); 215 if (!this.baseUrl.endsWith("/")) { 216 this.baseUrl += "/"; 217 } 218 } 219 220 /** 221 * Return the Oozie URL of the workflow client instance. 222 * <p/> 223 * This URL is the base URL fo the Oozie system, with not protocol versioning. 224 * 225 * @return the Oozie URL of the workflow client instance. 226 */ 227 public String getOozieUrl() { 228 return baseUrl; 229 } 230 231 /** 232 * Return the Oozie URL used by the client and server for WS communications. 233 * <p/> 234 * This URL is the original URL plus the versioning element path. 235 * 236 * @return the Oozie URL used by the client and server for communication. 237 * @throws OozieClientException thrown in the client and the server are not protocol compatible. 238 */ 239 public String getProtocolUrl() throws OozieClientException { 240 validateWSVersion(); 241 return protocolUrl; 242 } 243 244 /** 245 * @return current debug Mode 246 */ 247 public int getDebugMode() { 248 return debugMode; 249 } 250 251 /** 252 * Set debug mode. 253 * 254 * @param debugMode : 0 means no debugging. > 0 means debugging 255 */ 256 public void setDebugMode(int debugMode) { 257 this.debugMode = debugMode; 258 } 259 260 public int getRetryCount() { 261 return retryCount; 262 } 263 264 265 public void setRetryCount(int retryCount) { 266 this.retryCount = retryCount; 267 } 268 269 private String getBaseURLForVersion(long protocolVersion) throws OozieClientException { 270 try { 271 if (supportedVersions == null) { 272 supportedVersions = getSupportedProtocolVersions(); 273 } 274 if (supportedVersions == null) { 275 throw new OozieClientException("HTTP error", "no response message"); 276 } 277 if (supportedVersions.contains(protocolVersion)) { 278 return baseUrl + "v" + protocolVersion + "/"; 279 } 280 else { 281 throw new OozieClientException(OozieClientException.UNSUPPORTED_VERSION, "Protocol version " 282 + protocolVersion + " is not supported"); 283 } 284 } 285 catch (IOException e) { 286 throw new OozieClientException(OozieClientException.IO_ERROR, e); 287 } 288 } 289 290 /** 291 * Validate that the Oozie client and server instances are protocol compatible. 292 * 293 * @throws OozieClientException thrown in the client and the server are not protocol compatible. 294 */ 295 public synchronized void validateWSVersion() throws OozieClientException { 296 if (!validatedVersion) { 297 try { 298 supportedVersions = getSupportedProtocolVersions(); 299 if (supportedVersions == null) { 300 throw new OozieClientException("HTTP error", "no response message"); 301 } 302 if (!supportedVersions.contains(WS_PROTOCOL_VERSION) 303 && !supportedVersions.contains(WS_PROTOCOL_VERSION_1) 304 && !supportedVersions.contains(WS_PROTOCOL_VERSION_0)) { 305 StringBuilder msg = new StringBuilder(); 306 msg.append("Supported version [").append(WS_PROTOCOL_VERSION) 307 .append("] or less, Unsupported versions["); 308 String separator = ""; 309 for (Object version : supportedVersions) { 310 msg.append(separator).append(version); 311 } 312 msg.append("]"); 313 throw new OozieClientException(OozieClientException.UNSUPPORTED_VERSION, msg.toString()); 314 } 315 if (supportedVersions.contains(WS_PROTOCOL_VERSION)) { 316 protocolUrl = baseUrl + "v" + WS_PROTOCOL_VERSION + "/"; 317 } 318 else if (supportedVersions.contains(WS_PROTOCOL_VERSION_1)) { 319 protocolUrl = baseUrl + "v" + WS_PROTOCOL_VERSION_1 + "/"; 320 } 321 else { 322 if (supportedVersions.contains(WS_PROTOCOL_VERSION_0)) { 323 protocolUrl = baseUrl + "v" + WS_PROTOCOL_VERSION_0 + "/"; 324 } 325 } 326 } 327 catch (IOException ex) { 328 throw new OozieClientException(OozieClientException.IO_ERROR, ex); 329 } 330 validatedVersion = true; 331 } 332 } 333 334 private JSONArray getSupportedProtocolVersions() throws IOException, OozieClientException { 335 JSONArray versions = null; 336 final URL url = new URL(baseUrl + RestConstants.VERSIONS); 337 338 HttpURLConnection conn = createRetryableConnection(url, "GET"); 339 340 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { 341 versions = (JSONArray) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 342 } 343 else { 344 handleError(conn); 345 } 346 return versions; 347 } 348 349 /** 350 * Create an empty configuration with just the {@link #USER_NAME} set to the JVM user name. 351 * 352 * @return an empty configuration. 353 */ 354 public Properties createConfiguration() { 355 Properties conf = new Properties(); 356 String userName = USER_NAME_TL.get(); 357 if (userName == null) { 358 userName = System.getProperty("user.name"); 359 } 360 conf.setProperty(USER_NAME, userName); 361 return conf; 362 } 363 364 /** 365 * Set a HTTP header to be used in the WS requests by the workflow instance. 366 * 367 * @param name header name. 368 * @param value header value. 369 */ 370 public void setHeader(String name, String value) { 371 headers.put(notEmpty(name, "name"), notNull(value, "value")); 372 } 373 374 /** 375 * Get the value of a set HTTP header from the workflow instance. 376 * 377 * @param name header name. 378 * @return header value, <code>null</code> if not set. 379 */ 380 public String getHeader(String name) { 381 return headers.get(notEmpty(name, "name")); 382 } 383 384 /** 385 * Get the set HTTP header 386 * 387 * @return map of header key and value 388 */ 389 public Map<String, String> getHeaders() { 390 return headers; 391 } 392 393 /** 394 * Remove a HTTP header from the workflow client instance. 395 * 396 * @param name header name. 397 */ 398 public void removeHeader(String name) { 399 headers.remove(notEmpty(name, "name")); 400 } 401 402 /** 403 * Return an iterator with all the header names set in the workflow instance. 404 * 405 * @return header names. 406 */ 407 public Iterator<String> getHeaderNames() { 408 return Collections.unmodifiableMap(headers).keySet().iterator(); 409 } 410 411 private URL createURL(Long protocolVersion, String collection, String resource, Map<String, String> parameters) 412 throws IOException, OozieClientException { 413 validateWSVersion(); 414 StringBuilder sb = new StringBuilder(); 415 if (protocolVersion == null) { 416 sb.append(protocolUrl); 417 } 418 else { 419 sb.append(getBaseURLForVersion(protocolVersion)); 420 } 421 sb.append(collection); 422 if (resource != null && resource.length() > 0) { 423 sb.append("/").append(resource); 424 } 425 if (parameters.size() > 0) { 426 String separator = "?"; 427 for (Map.Entry<String, String> param : parameters.entrySet()) { 428 if (param.getValue() != null) { 429 sb.append(separator).append(URLEncoder.encode(param.getKey(), "UTF-8")).append("=").append( 430 URLEncoder.encode(param.getValue(), "UTF-8")); 431 separator = "&"; 432 } 433 } 434 } 435 return new URL(sb.toString()); 436 } 437 438 private boolean validateCommand(String url) { 439 { 440 if (protocolUrl.contains(baseUrl + "v0")) { 441 if (url.contains("dryrun") || url.contains("jobtype=c") || url.contains("systemmode")) { 442 return false; 443 } 444 } 445 } 446 return true; 447 } 448 /** 449 * Create retryable http connection to oozie server. 450 * 451 * @param url 452 * @param method 453 * @return connection 454 * @throws IOException 455 * @throws OozieClientException 456 */ 457 protected HttpURLConnection createRetryableConnection(final URL url, final String method) throws IOException{ 458 return (HttpURLConnection) new ConnectionRetriableClient(getRetryCount()) { 459 @Override 460 public Object doExecute(URL url, String method) throws IOException, OozieClientException { 461 HttpURLConnection conn = createConnection(url, method); 462 return conn; 463 } 464 }.execute(url, method); 465 } 466 467 /** 468 * Create http connection to oozie server. 469 * 470 * @param url 471 * @param method 472 * @return connection 473 * @throws IOException 474 * @throws OozieClientException 475 */ 476 protected HttpURLConnection createConnection(URL url, String method) throws IOException, OozieClientException { 477 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 478 conn.setRequestMethod(method); 479 if (method.equals("POST") || method.equals("PUT")) { 480 conn.setDoOutput(true); 481 } 482 for (Map.Entry<String, String> header : headers.entrySet()) { 483 conn.setRequestProperty(header.getKey(), header.getValue()); 484 } 485 return conn; 486 } 487 488 protected abstract class ClientCallable<T> implements Callable<T> { 489 private final String method; 490 private final String collection; 491 private final String resource; 492 private final Map<String, String> params; 493 private final Long protocolVersion; 494 495 public ClientCallable(String method, String collection, String resource, Map<String, String> params) { 496 this(method, null, collection, resource, params); 497 } 498 499 public ClientCallable(String method, Long protocolVersion, String collection, String resource, Map<String, String> params) { 500 this.method = method; 501 this.protocolVersion = protocolVersion; 502 this.collection = collection; 503 this.resource = resource; 504 this.params = params; 505 } 506 507 public T call() throws OozieClientException { 508 try { 509 URL url = createURL(protocolVersion, collection, resource, params); 510 if (validateCommand(url.toString())) { 511 if (getDebugMode() > 0) { 512 System.out.println(method + " " + url); 513 } 514 return call(createRetryableConnection(url, method)); 515 } 516 else { 517 System.out.println("Option not supported in target server. Supported only on Oozie-2.0 or greater." 518 + " Use 'oozie help' for details"); 519 throw new OozieClientException(OozieClientException.UNSUPPORTED_VERSION, new Exception()); 520 } 521 } 522 catch (IOException ex) { 523 throw new OozieClientException(OozieClientException.IO_ERROR, ex); 524 } 525 } 526 527 protected abstract T call(HttpURLConnection conn) throws IOException, OozieClientException; 528 } 529 530 static void handleError(HttpURLConnection conn) throws IOException, OozieClientException { 531 int status = conn.getResponseCode(); 532 String error = conn.getHeaderField(RestConstants.OOZIE_ERROR_CODE); 533 String message = conn.getHeaderField(RestConstants.OOZIE_ERROR_MESSAGE); 534 535 if (error == null) { 536 error = "HTTP error code: " + status; 537 } 538 539 if (message == null) { 540 message = conn.getResponseMessage(); 541 } 542 throw new OozieClientException(error, message); 543 } 544 545 static Map<String, String> prepareParams(String... params) { 546 Map<String, String> map = new LinkedHashMap<String, String>(); 547 for (int i = 0; i < params.length; i = i + 2) { 548 map.put(params[i], params[i + 1]); 549 } 550 String doAsUserName = USER_NAME_TL.get(); 551 if (doAsUserName != null) { 552 map.put(RestConstants.DO_AS_PARAM, doAsUserName); 553 } 554 return map; 555 } 556 557 public void writeToXml(Properties props, OutputStream out) throws IOException { 558 try { 559 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 560 Element conf = doc.createElement("configuration"); 561 doc.appendChild(conf); 562 conf.appendChild(doc.createTextNode("\n")); 563 for (String name : props.stringPropertyNames()) { // Properties whose key or value is not of type String are omitted. 564 String value = props.getProperty(name); 565 Element propNode = doc.createElement("property"); 566 conf.appendChild(propNode); 567 568 Element nameNode = doc.createElement("name"); 569 nameNode.appendChild(doc.createTextNode(name.trim())); 570 propNode.appendChild(nameNode); 571 572 Element valueNode = doc.createElement("value"); 573 valueNode.appendChild(doc.createTextNode(value.trim())); 574 propNode.appendChild(valueNode); 575 576 conf.appendChild(doc.createTextNode("\n")); 577 } 578 579 DOMSource source = new DOMSource(doc); 580 StreamResult result = new StreamResult(out); 581 TransformerFactory transFactory = TransformerFactory.newInstance(); 582 Transformer transformer = transFactory.newTransformer(); 583 transformer.transform(source, result); 584 if (getDebugMode() > 0) { 585 result = new StreamResult(System.out); 586 transformer.transform(source, result); 587 System.out.println(); 588 } 589 } 590 catch (Exception e) { 591 throw new IOException(e); 592 } 593 } 594 595 private class JobSubmit extends ClientCallable<String> { 596 private final Properties conf; 597 598 JobSubmit(Properties conf, boolean start) { 599 super("POST", RestConstants.JOBS, "", (start) ? prepareParams(RestConstants.ACTION_PARAM, 600 RestConstants.JOB_ACTION_START) : prepareParams()); 601 this.conf = notNull(conf, "conf"); 602 } 603 604 JobSubmit(String jobId, Properties conf) { 605 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 606 RestConstants.JOB_ACTION_RERUN)); 607 this.conf = notNull(conf, "conf"); 608 } 609 610 public JobSubmit(Properties conf, String jobActionDryrun) { 611 super("POST", RestConstants.JOBS, "", prepareParams(RestConstants.ACTION_PARAM, 612 RestConstants.JOB_ACTION_DRYRUN)); 613 this.conf = notNull(conf, "conf"); 614 } 615 616 @Override 617 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 618 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 619 writeToXml(conf, conn.getOutputStream()); 620 if (conn.getResponseCode() == HttpURLConnection.HTTP_CREATED) { 621 JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 622 return (String) json.get(JsonTags.JOB_ID); 623 } 624 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 625 handleError(conn); 626 } 627 return null; 628 } 629 } 630 631 /** 632 * Submit a workflow job. 633 * 634 * @param conf job configuration. 635 * @return the job Id. 636 * @throws OozieClientException thrown if the job could not be submitted. 637 */ 638 public String submit(Properties conf) throws OozieClientException { 639 return (new JobSubmit(conf, false)).call(); 640 } 641 642 private class JobAction extends ClientCallable<Void> { 643 644 JobAction(String jobId, String action) { 645 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, action)); 646 } 647 648 JobAction(String jobId, String action, String params) { 649 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, action, 650 RestConstants.JOB_CHANGE_VALUE, params)); 651 } 652 653 @Override 654 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 655 if (!(conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 656 handleError(conn); 657 } 658 return null; 659 } 660 } 661 662 /** 663 * Update coord definition. 664 * 665 * @param jobId the job id 666 * @param conf the conf 667 * @param dryrun the dryrun 668 * @param showDiff the show diff 669 * @return the string 670 * @throws OozieClientException the oozie client exception 671 */ 672 public String updateCoord(String jobId, Properties conf, String dryrun, String showDiff) 673 throws OozieClientException { 674 return (new UpdateCoord(jobId, conf, dryrun, showDiff)).call(); 675 } 676 677 /** 678 * Update coord definition without properties. 679 * 680 * @param jobId the job id 681 * @param dryrun the dryrun 682 * @param showDiff the show diff 683 * @return the string 684 * @throws OozieClientException the oozie client exception 685 */ 686 public String updateCoord(String jobId, String dryrun, String showDiff) throws OozieClientException { 687 return (new UpdateCoord(jobId, dryrun, showDiff)).call(); 688 } 689 690 /** 691 * The Class UpdateCoord. 692 */ 693 private class UpdateCoord extends ClientCallable<String> { 694 private final Properties conf; 695 696 public UpdateCoord(String jobId, Properties conf, String jobActionDryrun, String showDiff) { 697 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 698 RestConstants.JOB_COORD_UPDATE, RestConstants.JOB_ACTION_DRYRUN, jobActionDryrun, 699 RestConstants.JOB_ACTION_SHOWDIFF, showDiff)); 700 this.conf = conf; 701 } 702 703 public UpdateCoord(String jobId, String jobActionDryrun, String showDiff) { 704 this(jobId, new Properties(), jobActionDryrun, showDiff); 705 } 706 707 @Override 708 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 709 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 710 writeToXml(conf, conn.getOutputStream()); 711 712 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { 713 JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 714 JSONObject update = (JSONObject) json.get(JsonTags.COORD_UPDATE); 715 if (update != null) { 716 return (String) update.get(JsonTags.COORD_UPDATE_DIFF); 717 } 718 else { 719 return ""; 720 } 721 } 722 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 723 handleError(conn); 724 } 725 return null; 726 } 727 } 728 729 /** 730 * dryrun for a given job 731 * 732 * @param conf Job configuration. 733 */ 734 public String dryrun(Properties conf) throws OozieClientException { 735 return new JobSubmit(conf, RestConstants.JOB_ACTION_DRYRUN).call(); 736 } 737 738 /** 739 * Start a workflow job. 740 * 741 * @param jobId job Id. 742 * @throws OozieClientException thrown if the job could not be started. 743 */ 744 public void start(String jobId) throws OozieClientException { 745 new JobAction(jobId, RestConstants.JOB_ACTION_START).call(); 746 } 747 748 /** 749 * Submit and start a workflow job. 750 * 751 * @param conf job configuration. 752 * @return the job Id. 753 * @throws OozieClientException thrown if the job could not be submitted. 754 */ 755 public String run(Properties conf) throws OozieClientException { 756 return (new JobSubmit(conf, true)).call(); 757 } 758 759 /** 760 * Rerun a workflow job. 761 * 762 * @param jobId job Id to rerun. 763 * @param conf configuration information for the rerun. 764 * @throws OozieClientException thrown if the job could not be started. 765 */ 766 public void reRun(String jobId, Properties conf) throws OozieClientException { 767 new JobSubmit(jobId, conf).call(); 768 } 769 770 /** 771 * Suspend a workflow job. 772 * 773 * @param jobId job Id. 774 * @throws OozieClientException thrown if the job could not be suspended. 775 */ 776 public void suspend(String jobId) throws OozieClientException { 777 new JobAction(jobId, RestConstants.JOB_ACTION_SUSPEND).call(); 778 } 779 780 /** 781 * Resume a workflow job. 782 * 783 * @param jobId job Id. 784 * @throws OozieClientException thrown if the job could not be resume. 785 */ 786 public void resume(String jobId) throws OozieClientException { 787 new JobAction(jobId, RestConstants.JOB_ACTION_RESUME).call(); 788 } 789 790 /** 791 * Kill a workflow/coord/bundle job. 792 * 793 * @param jobId job Id. 794 * @throws OozieClientException thrown if the job could not be killed. 795 */ 796 public void kill(String jobId) throws OozieClientException { 797 new JobAction(jobId, RestConstants.JOB_ACTION_KILL).call(); 798 } 799 800 /** 801 * Kill coordinator actions 802 * @param jobId coordinator Job Id 803 * @param rangeType type 'date' if -date is used, 'action-num' if -action is used 804 * @param scope kill scope for date or action nums 805 * @return list of coordinator actions that underwent kill 806 * @throws OozieClientException thrown if some actions could not be killed. 807 */ 808 public List<CoordinatorAction> kill(String jobId, String rangeType, String scope) throws OozieClientException { 809 return new CoordActionsKill(jobId, rangeType, scope).call(); 810 } 811 812 /** 813 * Change a coordinator job. 814 * 815 * @param jobId job Id. 816 * @param changeValue change value. 817 * @throws OozieClientException thrown if the job could not be changed. 818 */ 819 public void change(String jobId, String changeValue) throws OozieClientException { 820 new JobAction(jobId, RestConstants.JOB_ACTION_CHANGE, changeValue).call(); 821 } 822 823 /** 824 * Ignore a coordinator job. 825 * 826 * @param jobId coord job Id. 827 * @param scope list of coord actions to be ignored 828 * @throws OozieClientException thrown if the job could not be changed. 829 */ 830 public List<CoordinatorAction> ignore(String jobId, String scope) throws OozieClientException { 831 return new CoordIgnore(jobId, RestConstants.JOB_COORD_SCOPE_ACTION, scope).call(); 832 } 833 834 private class JobInfo extends ClientCallable<WorkflowJob> { 835 836 JobInfo(String jobId, int start, int len) { 837 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 838 RestConstants.JOB_SHOW_INFO, RestConstants.OFFSET_PARAM, Integer.toString(start), 839 RestConstants.LEN_PARAM, Integer.toString(len))); 840 } 841 842 @Override 843 protected WorkflowJob call(HttpURLConnection conn) throws IOException, OozieClientException { 844 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 845 Reader reader = new InputStreamReader(conn.getInputStream()); 846 JSONObject json = (JSONObject) JSONValue.parse(reader); 847 return JsonToBean.createWorkflowJob(json); 848 } 849 else { 850 handleError(conn); 851 } 852 return null; 853 } 854 } 855 856 private class JMSInfo extends ClientCallable<JMSConnectionInfo> { 857 858 JMSInfo() { 859 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_JMS_INFO, prepareParams()); 860 } 861 862 protected JMSConnectionInfo call(HttpURLConnection conn) throws IOException, OozieClientException { 863 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 864 Reader reader = new InputStreamReader(conn.getInputStream()); 865 JSONObject json = (JSONObject) JSONValue.parse(reader); 866 return JsonToBean.createJMSConnectionInfo(json); 867 } 868 else { 869 handleError(conn); 870 } 871 return null; 872 } 873 } 874 875 private class WorkflowActionInfo extends ClientCallable<WorkflowAction> { 876 WorkflowActionInfo(String actionId) { 877 super("GET", RestConstants.JOB, notEmpty(actionId, "id"), prepareParams(RestConstants.JOB_SHOW_PARAM, 878 RestConstants.JOB_SHOW_INFO)); 879 } 880 881 @Override 882 protected WorkflowAction call(HttpURLConnection conn) throws IOException, OozieClientException { 883 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 884 Reader reader = new InputStreamReader(conn.getInputStream()); 885 JSONObject json = (JSONObject) JSONValue.parse(reader); 886 return JsonToBean.createWorkflowAction(json); 887 } 888 else { 889 handleError(conn); 890 } 891 return null; 892 } 893 } 894 895 /** 896 * Get the info of a workflow job. 897 * 898 * @param jobId job Id. 899 * @return the job info. 900 * @throws OozieClientException thrown if the job info could not be retrieved. 901 */ 902 public WorkflowJob getJobInfo(String jobId) throws OozieClientException { 903 return getJobInfo(jobId, 0, 0); 904 } 905 906 /** 907 * Get the JMS Connection info 908 * @return JMSConnectionInfo object 909 * @throws OozieClientException 910 */ 911 public JMSConnectionInfo getJMSConnectionInfo() throws OozieClientException { 912 return new JMSInfo().call(); 913 } 914 915 /** 916 * Get the info of a workflow job and subset actions. 917 * 918 * @param jobId job Id. 919 * @param start starting index in the list of actions belonging to the job 920 * @param len number of actions to be returned 921 * @return the job info. 922 * @throws OozieClientException thrown if the job info could not be retrieved. 923 */ 924 public WorkflowJob getJobInfo(String jobId, int start, int len) throws OozieClientException { 925 return new JobInfo(jobId, start, len).call(); 926 } 927 928 /** 929 * Get the info of a workflow action. 930 * 931 * @param actionId Id. 932 * @return the workflow action info. 933 * @throws OozieClientException thrown if the job info could not be retrieved. 934 */ 935 public WorkflowAction getWorkflowActionInfo(String actionId) throws OozieClientException { 936 return new WorkflowActionInfo(actionId).call(); 937 } 938 939 /** 940 * Get the log of a workflow job. 941 * 942 * @param jobId job Id. 943 * @return the job log. 944 * @throws OozieClientException thrown if the job info could not be retrieved. 945 */ 946 public String getJobLog(String jobId) throws OozieClientException { 947 return new JobLog(jobId).call(); 948 } 949 950 /** 951 * Get the log of a job. 952 * 953 * @param jobId job Id. 954 * @param logRetrievalType Based on which filter criteria the log is retrieved 955 * @param logRetrievalScope Value for the retrieval type 956 * @param logFilter log filter 957 * @param ps Printstream of command line interface 958 * @throws OozieClientException thrown if the job info could not be retrieved. 959 */ 960 public void getJobLog(String jobId, String logRetrievalType, String logRetrievalScope, String logFilter, 961 PrintStream ps) throws OozieClientException { 962 new JobLog(jobId, logRetrievalType, logRetrievalScope, logFilter, ps).call(); 963 } 964 965 /** 966 * Get the log of a job. 967 * 968 * @param jobId job Id. 969 * @param logRetrievalType Based on which filter criteria the log is retrieved 970 * @param logRetrievalScope Value for the retrieval type 971 * @param ps Printstream of command line interface 972 * @throws OozieClientException thrown if the job info could not be retrieved. 973 */ 974 public void getJobLog(String jobId, String logRetrievalType, String logRetrievalScope, PrintStream ps) 975 throws OozieClientException { 976 getJobLog(jobId, logRetrievalType, logRetrievalScope, null, ps); 977 } 978 979 private class JobLog extends JobMetadata { 980 JobLog(String jobId) { 981 super(jobId, RestConstants.JOB_SHOW_LOG); 982 } 983 JobLog(String jobId, String logRetrievalType, String logRetrievalScope, String logFilter, PrintStream ps) { 984 super(jobId, logRetrievalType, logRetrievalScope, RestConstants.JOB_SHOW_LOG, logFilter, ps); 985 } 986 } 987 988 /** 989 * Gets the JMS topic name for a particular job 990 * @param jobId given jobId 991 * @return the JMS topic name 992 * @throws OozieClientException 993 */ 994 public String getJMSTopicName(String jobId) throws OozieClientException { 995 return new JMSTopic(jobId).call(); 996 } 997 998 private class JMSTopic extends ClientCallable<String> { 999 1000 JMSTopic(String jobId) { 1001 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1002 RestConstants.JOB_SHOW_JMS_TOPIC)); 1003 } 1004 1005 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1006 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1007 Reader reader = new InputStreamReader(conn.getInputStream()); 1008 JSONObject json = (JSONObject) JSONValue.parse(reader); 1009 return (String) json.get(JsonTags.JMS_TOPIC_NAME); 1010 } 1011 else { 1012 handleError(conn); 1013 } 1014 return null; 1015 } 1016 } 1017 1018 /** 1019 * Get the definition of a workflow job. 1020 * 1021 * @param jobId job Id. 1022 * @return the job log. 1023 * @throws OozieClientException thrown if the job info could not be retrieved. 1024 */ 1025 public String getJobDefinition(String jobId) throws OozieClientException { 1026 return new JobDefinition(jobId).call(); 1027 } 1028 1029 private class JobDefinition extends JobMetadata { 1030 1031 JobDefinition(String jobId) { 1032 super(jobId, RestConstants.JOB_SHOW_DEFINITION); 1033 } 1034 } 1035 1036 private class JobMetadata extends ClientCallable<String> { 1037 PrintStream printStream; 1038 1039 JobMetadata(String jobId, String metaType) { 1040 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1041 metaType)); 1042 } 1043 1044 JobMetadata(String jobId, String logRetrievalType, String logRetrievalScope, String metaType, String logFilter, 1045 PrintStream ps) { 1046 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1047 metaType, RestConstants.JOB_LOG_TYPE_PARAM, logRetrievalType, RestConstants.JOB_LOG_SCOPE_PARAM, 1048 logRetrievalScope, RestConstants.LOG_FILTER_OPTION, logFilter)); 1049 printStream = ps; 1050 } 1051 1052 @Override 1053 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1054 String returnVal = null; 1055 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1056 InputStream is = conn.getInputStream(); 1057 InputStreamReader isr = new InputStreamReader(is); 1058 try { 1059 if (printStream != null) { 1060 sendToOutputStream(isr, -1); 1061 } 1062 else { 1063 returnVal = getReaderAsString(isr, -1); 1064 } 1065 } 1066 finally { 1067 isr.close(); 1068 } 1069 } 1070 else { 1071 handleError(conn); 1072 } 1073 return returnVal; 1074 } 1075 1076 /** 1077 * Output the log to command line interface 1078 * 1079 * @param reader reader to read into a string. 1080 * @param maxLen max content length allowed, if -1 there is no limit. 1081 * @throws IOException 1082 */ 1083 private void sendToOutputStream(Reader reader, int maxLen) throws IOException { 1084 if (reader == null) { 1085 throw new IllegalArgumentException("reader cannot be null"); 1086 } 1087 StringBuilder sb = new StringBuilder(); 1088 char[] buffer = new char[2048]; 1089 int read; 1090 int count = 0; 1091 int noOfCharstoFlush = 1024; 1092 while ((read = reader.read(buffer)) > -1) { 1093 count += read; 1094 if ((maxLen > -1) && (count > maxLen)) { 1095 break; 1096 } 1097 sb.append(buffer, 0, read); 1098 if (sb.length() > noOfCharstoFlush) { 1099 printStream.print(sb.toString()); 1100 sb = new StringBuilder(""); 1101 } 1102 } 1103 printStream.print(sb.toString()); 1104 } 1105 1106 /** 1107 * Return a reader as string. 1108 * <p/> 1109 * 1110 * @param reader reader to read into a string. 1111 * @param maxLen max content length allowed, if -1 there is no limit. 1112 * @return the reader content. 1113 * @throws IOException thrown if the resource could not be read. 1114 */ 1115 private String getReaderAsString(Reader reader, int maxLen) throws IOException { 1116 if (reader == null) { 1117 throw new IllegalArgumentException("reader cannot be null"); 1118 } 1119 StringBuffer sb = new StringBuffer(); 1120 char[] buffer = new char[2048]; 1121 int read; 1122 int count = 0; 1123 while ((read = reader.read(buffer)) > -1) { 1124 count += read; 1125 1126 // read up to maxLen chars; 1127 if ((maxLen > -1) && (count > maxLen)) { 1128 break; 1129 } 1130 sb.append(buffer, 0, read); 1131 } 1132 reader.close(); 1133 return sb.toString(); 1134 } 1135 } 1136 1137 private class CoordJobInfo extends ClientCallable<CoordinatorJob> { 1138 1139 CoordJobInfo(String jobId, String filter, int start, int len, String order) { 1140 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1141 RestConstants.JOB_SHOW_INFO, RestConstants.JOB_FILTER_PARAM, filter, RestConstants.OFFSET_PARAM, 1142 Integer.toString(start), RestConstants.LEN_PARAM, Integer.toString(len), RestConstants.ORDER_PARAM, 1143 order)); 1144 } 1145 1146 @Override 1147 protected CoordinatorJob call(HttpURLConnection conn) throws IOException, OozieClientException { 1148 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1149 Reader reader = new InputStreamReader(conn.getInputStream()); 1150 JSONObject json = (JSONObject) JSONValue.parse(reader); 1151 return JsonToBean.createCoordinatorJob(json); 1152 } 1153 else { 1154 handleError(conn); 1155 } 1156 return null; 1157 } 1158 } 1159 1160 private class WfsForCoordAction extends ClientCallable<List<WorkflowJob>> { 1161 1162 WfsForCoordAction(String coordActionId) { 1163 super("GET", RestConstants.JOB, notEmpty(coordActionId, "coordActionId"), prepareParams( 1164 RestConstants.JOB_SHOW_PARAM, RestConstants.ALL_WORKFLOWS_FOR_COORD_ACTION)); 1165 } 1166 1167 @Override 1168 protected List<WorkflowJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1169 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1170 Reader reader = new InputStreamReader(conn.getInputStream()); 1171 JSONObject json = (JSONObject) JSONValue.parse(reader); 1172 JSONArray workflows = (JSONArray) json.get(JsonTags.WORKFLOWS_JOBS); 1173 if (workflows == null) { 1174 workflows = new JSONArray(); 1175 } 1176 return JsonToBean.createWorkflowJobList(workflows); 1177 } 1178 else { 1179 handleError(conn); 1180 } 1181 return null; 1182 } 1183 } 1184 1185 1186 private class BundleJobInfo extends ClientCallable<BundleJob> { 1187 1188 BundleJobInfo(String jobId) { 1189 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1190 RestConstants.JOB_SHOW_INFO)); 1191 } 1192 1193 @Override 1194 protected BundleJob call(HttpURLConnection conn) throws IOException, OozieClientException { 1195 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1196 Reader reader = new InputStreamReader(conn.getInputStream()); 1197 JSONObject json = (JSONObject) JSONValue.parse(reader); 1198 return JsonToBean.createBundleJob(json); 1199 } 1200 else { 1201 handleError(conn); 1202 } 1203 return null; 1204 } 1205 } 1206 1207 private class CoordActionInfo extends ClientCallable<CoordinatorAction> { 1208 CoordActionInfo(String actionId) { 1209 super("GET", RestConstants.JOB, notEmpty(actionId, "id"), prepareParams(RestConstants.JOB_SHOW_PARAM, 1210 RestConstants.JOB_SHOW_INFO)); 1211 } 1212 1213 @Override 1214 protected CoordinatorAction call(HttpURLConnection conn) throws IOException, OozieClientException { 1215 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1216 Reader reader = new InputStreamReader(conn.getInputStream()); 1217 JSONObject json = (JSONObject) JSONValue.parse(reader); 1218 return JsonToBean.createCoordinatorAction(json); 1219 } 1220 else { 1221 handleError(conn); 1222 } 1223 return null; 1224 } 1225 } 1226 1227 /** 1228 * Get the info of a bundle job. 1229 * 1230 * @param jobId job Id. 1231 * @return the job info. 1232 * @throws OozieClientException thrown if the job info could not be retrieved. 1233 */ 1234 public BundleJob getBundleJobInfo(String jobId) throws OozieClientException { 1235 return new BundleJobInfo(jobId).call(); 1236 } 1237 1238 /** 1239 * Get the info of a coordinator job. 1240 * 1241 * @param jobId job Id. 1242 * @return the job info. 1243 * @throws OozieClientException thrown if the job info could not be retrieved. 1244 */ 1245 public CoordinatorJob getCoordJobInfo(String jobId) throws OozieClientException { 1246 return new CoordJobInfo(jobId, null, -1, -1, "asc").call(); 1247 } 1248 1249 /** 1250 * Get the info of a coordinator job and subset actions. 1251 * 1252 * @param jobId job Id. 1253 * @param filter filter the status filter 1254 * @param start starting index in the list of actions belonging to the job 1255 * @param len number of actions to be returned 1256 * @return the job info. 1257 * @throws OozieClientException thrown if the job info could not be retrieved. 1258 */ 1259 public CoordinatorJob getCoordJobInfo(String jobId, String filter, int start, int len) 1260 throws OozieClientException { 1261 return new CoordJobInfo(jobId, filter, start, len, "asc").call(); 1262 } 1263 1264 /** 1265 * Get the info of a coordinator job and subset actions. 1266 * 1267 * @param jobId job Id. 1268 * @param filter filter the status filter 1269 * @param start starting index in the list of actions belonging to the job 1270 * @param len number of actions to be returned 1271 * @param order order to list coord actions (e.g, desc) 1272 * @return the job info. 1273 * @throws OozieClientException thrown if the job info could not be retrieved. 1274 */ 1275 public CoordinatorJob getCoordJobInfo(String jobId, String filter, int start, int len, String order) 1276 throws OozieClientException { 1277 return new CoordJobInfo(jobId, filter, start, len, order).call(); 1278 } 1279 1280 public List<WorkflowJob> getWfsForCoordAction(String coordActionId) throws OozieClientException { 1281 return new WfsForCoordAction(coordActionId).call(); 1282 } 1283 1284 /** 1285 * Get the info of a coordinator action. 1286 * 1287 * @param actionId Id. 1288 * @return the coordinator action info. 1289 * @throws OozieClientException thrown if the job info could not be retrieved. 1290 */ 1291 public CoordinatorAction getCoordActionInfo(String actionId) throws OozieClientException { 1292 return new CoordActionInfo(actionId).call(); 1293 } 1294 1295 private class JobsStatus extends ClientCallable<List<WorkflowJob>> { 1296 1297 JobsStatus(String filter, int start, int len) { 1298 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 1299 RestConstants.JOBTYPE_PARAM, "wf", RestConstants.OFFSET_PARAM, Integer.toString(start), 1300 RestConstants.LEN_PARAM, Integer.toString(len))); 1301 } 1302 1303 @Override 1304 protected List<WorkflowJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1305 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1306 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1307 Reader reader = new InputStreamReader(conn.getInputStream()); 1308 JSONObject json = (JSONObject) JSONValue.parse(reader); 1309 JSONArray workflows = (JSONArray) json.get(JsonTags.WORKFLOWS_JOBS); 1310 if (workflows == null) { 1311 workflows = new JSONArray(); 1312 } 1313 return JsonToBean.createWorkflowJobList(workflows); 1314 } 1315 else { 1316 handleError(conn); 1317 } 1318 return null; 1319 } 1320 } 1321 1322 private class CoordJobsStatus extends ClientCallable<List<CoordinatorJob>> { 1323 1324 CoordJobsStatus(String filter, int start, int len) { 1325 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 1326 RestConstants.JOBTYPE_PARAM, "coord", RestConstants.OFFSET_PARAM, Integer.toString(start), 1327 RestConstants.LEN_PARAM, Integer.toString(len))); 1328 } 1329 1330 @Override 1331 protected List<CoordinatorJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1332 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1333 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1334 Reader reader = new InputStreamReader(conn.getInputStream()); 1335 JSONObject json = (JSONObject) JSONValue.parse(reader); 1336 JSONArray jobs = (JSONArray) json.get(JsonTags.COORDINATOR_JOBS); 1337 if (jobs == null) { 1338 jobs = new JSONArray(); 1339 } 1340 return JsonToBean.createCoordinatorJobList(jobs); 1341 } 1342 else { 1343 handleError(conn); 1344 } 1345 return null; 1346 } 1347 } 1348 1349 private class BundleJobsStatus extends ClientCallable<List<BundleJob>> { 1350 1351 BundleJobsStatus(String filter, int start, int len) { 1352 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 1353 RestConstants.JOBTYPE_PARAM, "bundle", RestConstants.OFFSET_PARAM, Integer.toString(start), 1354 RestConstants.LEN_PARAM, Integer.toString(len))); 1355 } 1356 1357 @Override 1358 protected List<BundleJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1359 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1360 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1361 Reader reader = new InputStreamReader(conn.getInputStream()); 1362 JSONObject json = (JSONObject) JSONValue.parse(reader); 1363 JSONArray jobs = (JSONArray) json.get(JsonTags.BUNDLE_JOBS); 1364 if (jobs == null) { 1365 jobs = new JSONArray(); 1366 } 1367 return JsonToBean.createBundleJobList(jobs); 1368 } 1369 else { 1370 handleError(conn); 1371 } 1372 return null; 1373 } 1374 } 1375 1376 private class BulkResponseStatus extends ClientCallable<List<BulkResponse>> { 1377 1378 BulkResponseStatus(String filter, int start, int len) { 1379 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_BULK_PARAM, filter, 1380 RestConstants.OFFSET_PARAM, Integer.toString(start), RestConstants.LEN_PARAM, Integer.toString(len))); 1381 } 1382 1383 @Override 1384 protected List<BulkResponse> call(HttpURLConnection conn) throws IOException, OozieClientException { 1385 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1386 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1387 Reader reader = new InputStreamReader(conn.getInputStream()); 1388 JSONObject json = (JSONObject) JSONValue.parse(reader); 1389 JSONArray results = (JSONArray) json.get(JsonTags.BULK_RESPONSES); 1390 if (results == null) { 1391 results = new JSONArray(); 1392 } 1393 return JsonToBean.createBulkResponseList(results); 1394 } 1395 else { 1396 handleError(conn); 1397 } 1398 return null; 1399 } 1400 } 1401 1402 private class CoordActionsKill extends ClientCallable<List<CoordinatorAction>> { 1403 1404 CoordActionsKill(String jobId, String rangeType, String scope) { 1405 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1406 RestConstants.JOB_ACTION_KILL, RestConstants.JOB_COORD_RANGE_TYPE_PARAM, rangeType, 1407 RestConstants.JOB_COORD_SCOPE_PARAM, scope)); 1408 } 1409 1410 @Override 1411 protected List<CoordinatorAction> call(HttpURLConnection conn) throws IOException, OozieClientException { 1412 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1413 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1414 Reader reader = new InputStreamReader(conn.getInputStream()); 1415 JSONObject json = (JSONObject) JSONValue.parse(reader); 1416 JSONArray coordActions = (JSONArray) json.get(JsonTags.COORDINATOR_ACTIONS); 1417 return JsonToBean.createCoordinatorActionList(coordActions); 1418 } 1419 else { 1420 handleError(conn); 1421 } 1422 return null; 1423 } 1424 } 1425 1426 private class CoordIgnore extends ClientCallable<List<CoordinatorAction>> { 1427 CoordIgnore(String jobId, String rerunType, String scope) { 1428 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1429 RestConstants.JOB_ACTION_IGNORE, RestConstants.JOB_COORD_RANGE_TYPE_PARAM, 1430 rerunType, RestConstants.JOB_COORD_SCOPE_PARAM, scope)); 1431 } 1432 1433 @Override 1434 protected List<CoordinatorAction> call(HttpURLConnection conn) throws IOException, OozieClientException { 1435 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1436 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1437 Reader reader = new InputStreamReader(conn.getInputStream()); 1438 JSONObject json = (JSONObject) JSONValue.parse(reader); 1439 if(json != null) { 1440 JSONArray coordActions = (JSONArray) json.get(JsonTags.COORDINATOR_ACTIONS); 1441 return JsonToBean.createCoordinatorActionList(coordActions); 1442 } 1443 } 1444 else { 1445 handleError(conn); 1446 } 1447 return null; 1448 } 1449 } 1450 private class CoordRerun extends ClientCallable<List<CoordinatorAction>> { 1451 1452 CoordRerun(String jobId, String rerunType, String scope, boolean refresh, boolean noCleanup) { 1453 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1454 RestConstants.JOB_COORD_ACTION_RERUN, RestConstants.JOB_COORD_RANGE_TYPE_PARAM, rerunType, 1455 RestConstants.JOB_COORD_SCOPE_PARAM, scope, RestConstants.JOB_COORD_RERUN_REFRESH_PARAM, 1456 Boolean.toString(refresh), RestConstants.JOB_COORD_RERUN_NOCLEANUP_PARAM, Boolean 1457 .toString(noCleanup))); 1458 } 1459 1460 @Override 1461 protected List<CoordinatorAction> call(HttpURLConnection conn) throws IOException, OozieClientException { 1462 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1463 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1464 Reader reader = new InputStreamReader(conn.getInputStream()); 1465 JSONObject json = (JSONObject) JSONValue.parse(reader); 1466 JSONArray coordActions = (JSONArray) json.get(JsonTags.COORDINATOR_ACTIONS); 1467 return JsonToBean.createCoordinatorActionList(coordActions); 1468 } 1469 else { 1470 handleError(conn); 1471 } 1472 return null; 1473 } 1474 } 1475 1476 private class BundleRerun extends ClientCallable<Void> { 1477 1478 BundleRerun(String jobId, String coordScope, String dateScope, boolean refresh, boolean noCleanup) { 1479 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1480 RestConstants.JOB_BUNDLE_ACTION_RERUN, RestConstants.JOB_BUNDLE_RERUN_COORD_SCOPE_PARAM, 1481 coordScope, RestConstants.JOB_BUNDLE_RERUN_DATE_SCOPE_PARAM, dateScope, 1482 RestConstants.JOB_COORD_RERUN_REFRESH_PARAM, Boolean.toString(refresh), 1483 RestConstants.JOB_COORD_RERUN_NOCLEANUP_PARAM, Boolean.toString(noCleanup))); 1484 } 1485 1486 @Override 1487 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1488 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1489 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1490 return null; 1491 } 1492 else { 1493 handleError(conn); 1494 } 1495 return null; 1496 } 1497 } 1498 1499 /** 1500 * Rerun coordinator actions. 1501 * 1502 * @param jobId coordinator jobId 1503 * @param rerunType rerun type 'date' if -date is used, 'action-id' if -action is used 1504 * @param scope rerun scope for date or actionIds 1505 * @param refresh true if -refresh is given in command option 1506 * @param noCleanup true if -nocleanup is given in command option 1507 * @throws OozieClientException 1508 */ 1509 public List<CoordinatorAction> reRunCoord(String jobId, String rerunType, String scope, boolean refresh, 1510 boolean noCleanup) throws OozieClientException { 1511 return new CoordRerun(jobId, rerunType, scope, refresh, noCleanup).call(); 1512 } 1513 1514 /** 1515 * Rerun bundle coordinators. 1516 * 1517 * @param jobId bundle jobId 1518 * @param coordScope rerun scope for coordinator jobs 1519 * @param dateScope rerun scope for date 1520 * @param refresh true if -refresh is given in command option 1521 * @param noCleanup true if -nocleanup is given in command option 1522 * @throws OozieClientException 1523 */ 1524 public Void reRunBundle(String jobId, String coordScope, String dateScope, boolean refresh, boolean noCleanup) 1525 throws OozieClientException { 1526 return new BundleRerun(jobId, coordScope, dateScope, refresh, noCleanup).call(); 1527 } 1528 1529 /** 1530 * Return the info of the workflow jobs that match the filter. 1531 * 1532 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1533 * @param start jobs offset, base 1. 1534 * @param len number of jobs to return. 1535 * @return a list with the workflow jobs info, without node details. 1536 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1537 */ 1538 public List<WorkflowJob> getJobsInfo(String filter, int start, int len) throws OozieClientException { 1539 return new JobsStatus(filter, start, len).call(); 1540 } 1541 1542 /** 1543 * Return the info of the workflow jobs that match the filter. 1544 * <p/> 1545 * It returns the first 100 jobs that match the filter. 1546 * 1547 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1548 * @return a list with the workflow jobs info, without node details. 1549 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1550 */ 1551 public List<WorkflowJob> getJobsInfo(String filter) throws OozieClientException { 1552 return getJobsInfo(filter, 1, 50); 1553 } 1554 1555 /** 1556 * Print sla info about coordinator and workflow jobs and actions. 1557 * 1558 * @param start starting offset 1559 * @param len number of results 1560 * @throws OozieClientException 1561 */ 1562 public void getSlaInfo(int start, int len, String filter) throws OozieClientException { 1563 new SlaInfo(start, len, filter).call(); 1564 } 1565 1566 private class SlaInfo extends ClientCallable<Void> { 1567 1568 SlaInfo(int start, int len, String filter) { 1569 super("GET", WS_PROTOCOL_VERSION_1, RestConstants.SLA, "", prepareParams(RestConstants.SLA_GT_SEQUENCE_ID, 1570 Integer.toString(start), RestConstants.MAX_EVENTS, Integer.toString(len), 1571 RestConstants.JOBS_FILTER_PARAM, filter)); 1572 } 1573 1574 @Override 1575 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1576 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1577 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1578 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); 1579 String line = null; 1580 while ((line = br.readLine()) != null) { 1581 System.out.println(line); 1582 } 1583 } 1584 else { 1585 handleError(conn); 1586 } 1587 return null; 1588 } 1589 } 1590 1591 private class JobIdAction extends ClientCallable<String> { 1592 1593 JobIdAction(String externalId) { 1594 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBTYPE_PARAM, "wf", 1595 RestConstants.JOBS_EXTERNAL_ID_PARAM, externalId)); 1596 } 1597 1598 @Override 1599 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1600 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1601 Reader reader = new InputStreamReader(conn.getInputStream()); 1602 JSONObject json = (JSONObject) JSONValue.parse(reader); 1603 return (String) json.get(JsonTags.JOB_ID); 1604 } 1605 else { 1606 handleError(conn); 1607 } 1608 return null; 1609 } 1610 } 1611 1612 /** 1613 * Return the workflow job Id for an external Id. 1614 * <p/> 1615 * The external Id must have provided at job creation time. 1616 * 1617 * @param externalId external Id given at job creation time. 1618 * @return the workflow job Id for an external Id, <code>null</code> if none. 1619 * @throws OozieClientException thrown if the operation could not be done. 1620 */ 1621 public String getJobId(String externalId) throws OozieClientException { 1622 return new JobIdAction(externalId).call(); 1623 } 1624 1625 private class SetSystemMode extends ClientCallable<Void> { 1626 1627 public SetSystemMode(SYSTEM_MODE status) { 1628 super("PUT", RestConstants.ADMIN, RestConstants.ADMIN_STATUS_RESOURCE, prepareParams( 1629 RestConstants.ADMIN_SYSTEM_MODE_PARAM, status + "")); 1630 } 1631 1632 @Override 1633 public Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1634 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 1635 handleError(conn); 1636 } 1637 return null; 1638 } 1639 } 1640 1641 /** 1642 * Enable or disable safe mode. Used by OozieCLI. In safe mode, Oozie would not accept any commands except status 1643 * command to change and view the safe mode status. 1644 * 1645 * @param status true to enable safe mode, false to disable safe mode. 1646 * @throws OozieClientException if it fails to set the safe mode status. 1647 */ 1648 public void setSystemMode(SYSTEM_MODE status) throws OozieClientException { 1649 new SetSystemMode(status).call(); 1650 } 1651 1652 private class GetSystemMode extends ClientCallable<SYSTEM_MODE> { 1653 1654 GetSystemMode() { 1655 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_STATUS_RESOURCE, prepareParams()); 1656 } 1657 1658 @Override 1659 protected SYSTEM_MODE call(HttpURLConnection conn) throws IOException, OozieClientException { 1660 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1661 Reader reader = new InputStreamReader(conn.getInputStream()); 1662 JSONObject json = (JSONObject) JSONValue.parse(reader); 1663 return SYSTEM_MODE.valueOf((String) json.get(JsonTags.OOZIE_SYSTEM_MODE)); 1664 } 1665 else { 1666 handleError(conn); 1667 } 1668 return SYSTEM_MODE.NORMAL; 1669 } 1670 } 1671 1672 /** 1673 * Returns if Oozie is in safe mode or not. 1674 * 1675 * @return true if safe mode is ON<br> 1676 * false if safe mode is OFF 1677 * @throws OozieClientException throw if it could not obtain the safe mode status. 1678 */ 1679 /* 1680 * public boolean isInSafeMode() throws OozieClientException { return new GetSafeMode().call(); } 1681 */ 1682 public SYSTEM_MODE getSystemMode() throws OozieClientException { 1683 return new GetSystemMode().call(); 1684 } 1685 1686 public String updateShareLib() throws OozieClientException { 1687 return new UpdateSharelib().call(); 1688 } 1689 1690 public String listShareLib(String sharelibKey) throws OozieClientException { 1691 return new ListShareLib(sharelibKey).call(); 1692 } 1693 1694 private class GetBuildVersion extends ClientCallable<String> { 1695 1696 GetBuildVersion() { 1697 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_BUILD_VERSION_RESOURCE, prepareParams()); 1698 } 1699 1700 @Override 1701 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1702 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1703 Reader reader = new InputStreamReader(conn.getInputStream()); 1704 JSONObject json = (JSONObject) JSONValue.parse(reader); 1705 return (String) json.get(JsonTags.BUILD_VERSION); 1706 } 1707 else { 1708 handleError(conn); 1709 } 1710 return null; 1711 } 1712 } 1713 1714 1715 private class UpdateSharelib extends ClientCallable<String> { 1716 1717 UpdateSharelib() { 1718 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_UPDATE_SHARELIB, prepareParams( 1719 RestConstants.ALL_SERVER_REQUEST, "true")); 1720 } 1721 1722 @Override 1723 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1724 StringBuffer bf = new StringBuffer(); 1725 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1726 Reader reader = new InputStreamReader(conn.getInputStream()); 1727 Object sharelib = (Object) JSONValue.parse(reader); 1728 bf.append("[ShareLib update status]").append(System.getProperty("line.separator")); 1729 if (sharelib instanceof JSONArray) { 1730 for (Object o : ((JSONArray) sharelib)) { 1731 JSONObject obj = (JSONObject) ((JSONObject) o).get(JsonTags.SHARELIB_LIB_UPDATE); 1732 for (Object key : obj.keySet()) { 1733 bf.append("\t").append(key).append(" = ").append(obj.get(key)) 1734 .append(System.getProperty("line.separator")); 1735 } 1736 bf.append(System.getProperty("line.separator")); 1737 } 1738 return bf.toString(); 1739 } 1740 else{ 1741 JSONObject obj = (JSONObject) ((JSONObject) sharelib).get(JsonTags.SHARELIB_LIB_UPDATE); 1742 for (Object key : obj.keySet()) { 1743 bf.append("\t").append(key).append(" = ").append(obj.get(key)) 1744 .append(System.getProperty("line.separator")); 1745 } 1746 bf.append(System.getProperty("line.separator")); 1747 } 1748 } 1749 else { 1750 handleError(conn); 1751 } 1752 return null; 1753 } 1754 } 1755 1756 private class ListShareLib extends ClientCallable<String> { 1757 1758 ListShareLib(String sharelibKey) { 1759 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_LIST_SHARELIB, prepareParams( 1760 RestConstants.SHARE_LIB_REQUEST_KEY, sharelibKey)); 1761 } 1762 1763 @Override 1764 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1765 1766 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1767 StringBuffer bf = new StringBuffer(); 1768 Reader reader = new InputStreamReader(conn.getInputStream()); 1769 JSONObject json = (JSONObject) JSONValue.parse(reader); 1770 Object sharelib = json.get(JsonTags.SHARELIB_LIB); 1771 bf.append("[Available ShareLib]").append(System.getProperty("line.separator")); 1772 if (sharelib instanceof JSONArray) { 1773 for (Object o : ((JSONArray) sharelib)) { 1774 JSONObject obj = (JSONObject) o; 1775 bf.append(obj.get(JsonTags.SHARELIB_LIB_NAME)) 1776 .append(System.getProperty("line.separator")); 1777 if (obj.get(JsonTags.SHARELIB_LIB_FILES) != null) { 1778 for (Object file : ((JSONArray) obj.get(JsonTags.SHARELIB_LIB_FILES))) { 1779 bf.append("\t").append(file).append(System.getProperty("line.separator")); 1780 } 1781 } 1782 } 1783 return bf.toString(); 1784 } 1785 } 1786 else { 1787 handleError(conn); 1788 } 1789 return null; 1790 } 1791 1792 } 1793 1794 /** 1795 * Return the Oozie server build version. 1796 * 1797 * @return the Oozie server build version. 1798 * @throws OozieClientException throw if it the server build version could not be retrieved. 1799 */ 1800 public String getServerBuildVersion() throws OozieClientException { 1801 return new GetBuildVersion().call(); 1802 } 1803 1804 /** 1805 * Return the Oozie client build version. 1806 * 1807 * @return the Oozie client build version. 1808 */ 1809 public String getClientBuildVersion() { 1810 return BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION); 1811 } 1812 1813 /** 1814 * Return the info of the coordinator jobs that match the filter. 1815 * 1816 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1817 * @param start jobs offset, base 1. 1818 * @param len number of jobs to return. 1819 * @return a list with the coordinator jobs info 1820 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1821 */ 1822 public List<CoordinatorJob> getCoordJobsInfo(String filter, int start, int len) throws OozieClientException { 1823 return new CoordJobsStatus(filter, start, len).call(); 1824 } 1825 1826 /** 1827 * Return the info of the bundle jobs that match the filter. 1828 * 1829 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1830 * @param start jobs offset, base 1. 1831 * @param len number of jobs to return. 1832 * @return a list with the bundle jobs info 1833 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1834 */ 1835 public List<BundleJob> getBundleJobsInfo(String filter, int start, int len) throws OozieClientException { 1836 return new BundleJobsStatus(filter, start, len).call(); 1837 } 1838 1839 public List<BulkResponse> getBulkInfo(String filter, int start, int len) throws OozieClientException { 1840 return new BulkResponseStatus(filter, start, len).call(); 1841 } 1842 1843 private class GetQueueDump extends ClientCallable<List<String>> { 1844 GetQueueDump() { 1845 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_QUEUE_DUMP_RESOURCE, prepareParams()); 1846 } 1847 1848 @Override 1849 protected List<String> call(HttpURLConnection conn) throws IOException, OozieClientException { 1850 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1851 Reader reader = new InputStreamReader(conn.getInputStream()); 1852 JSONObject json = (JSONObject) JSONValue.parse(reader); 1853 JSONArray queueDumpArray = (JSONArray) json.get(JsonTags.QUEUE_DUMP); 1854 1855 List<String> list = new ArrayList<String>(); 1856 list.add("[Server Queue Dump]:"); 1857 for (Object o : queueDumpArray) { 1858 JSONObject entry = (JSONObject) o; 1859 if (entry.get(JsonTags.CALLABLE_DUMP) != null) { 1860 String value = (String) entry.get(JsonTags.CALLABLE_DUMP); 1861 list.add(value); 1862 } 1863 } 1864 if (queueDumpArray.size() == 0) { 1865 list.add("Queue dump is null!"); 1866 } 1867 1868 list.add("******************************************"); 1869 list.add("[Server Uniqueness Map Dump]:"); 1870 1871 JSONArray uniqueDumpArray = (JSONArray) json.get(JsonTags.UNIQUE_MAP_DUMP); 1872 for (Object o : uniqueDumpArray) { 1873 JSONObject entry = (JSONObject) o; 1874 if (entry.get(JsonTags.UNIQUE_ENTRY_DUMP) != null) { 1875 String value = (String) entry.get(JsonTags.UNIQUE_ENTRY_DUMP); 1876 list.add(value); 1877 } 1878 } 1879 if (uniqueDumpArray.size() == 0) { 1880 list.add("Uniqueness dump is null!"); 1881 } 1882 return list; 1883 } 1884 else { 1885 handleError(conn); 1886 } 1887 return null; 1888 } 1889 } 1890 1891 /** 1892 * Return the Oozie queue's commands' dump 1893 * 1894 * @return the list of strings of callable identification in queue 1895 * @throws OozieClientException throw if it the queue dump could not be retrieved. 1896 */ 1897 public List<String> getQueueDump() throws OozieClientException { 1898 return new GetQueueDump().call(); 1899 } 1900 1901 private class GetAvailableOozieServers extends ClientCallable<Map<String, String>> { 1902 1903 GetAvailableOozieServers() { 1904 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_AVAILABLE_OOZIE_SERVERS_RESOURCE, prepareParams()); 1905 } 1906 1907 @Override 1908 protected Map<String, String> call(HttpURLConnection conn) throws IOException, OozieClientException { 1909 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1910 Reader reader = new InputStreamReader(conn.getInputStream()); 1911 JSONObject json = (JSONObject) JSONValue.parse(reader); 1912 Map<String, String> map = new HashMap<String, String>(); 1913 for (Object key : json.keySet()) { 1914 map.put((String)key, (String)json.get(key)); 1915 } 1916 return map; 1917 } 1918 else { 1919 handleError(conn); 1920 } 1921 return null; 1922 } 1923 } 1924 1925 /** 1926 * Return the list of available Oozie servers. 1927 * 1928 * @return the list of available Oozie servers. 1929 * @throws OozieClientException throw if it the list of available Oozie servers could not be retrieved. 1930 */ 1931 public Map<String, String> getAvailableOozieServers() throws OozieClientException { 1932 return new GetAvailableOozieServers().call(); 1933 } 1934 1935 1936 /** 1937 * Check if the string is not null or not empty. 1938 * 1939 * @param str 1940 * @param name 1941 * @return string 1942 */ 1943 public static String notEmpty(String str, String name) { 1944 if (str == null) { 1945 throw new IllegalArgumentException(name + " cannot be null"); 1946 } 1947 if (str.length() == 0) { 1948 throw new IllegalArgumentException(name + " cannot be empty"); 1949 } 1950 return str; 1951 } 1952 1953 /** 1954 * Check if the object is not null. 1955 * 1956 * @param <T> 1957 * @param obj 1958 * @param name 1959 * @return string 1960 */ 1961 public static <T> T notNull(T obj, String name) { 1962 if (obj == null) { 1963 throw new IllegalArgumentException(name + " cannot be null"); 1964 } 1965 return obj; 1966 } 1967 1968}