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 */ 018 package org.apache.oozie.client; 019 020 import java.io.BufferedReader; 021 import java.io.IOException; 022 import java.io.InputStream; 023 import java.io.InputStreamReader; 024 import java.io.OutputStream; 025 import java.io.PrintStream; 026 import java.io.Reader; 027 import java.net.HttpURLConnection; 028 import java.net.URL; 029 import java.net.URLEncoder; 030 import java.util.ArrayList; 031 import java.util.Collections; 032 import java.util.Enumeration; 033 import java.util.HashMap; 034 import java.util.Iterator; 035 import java.util.LinkedHashMap; 036 import java.util.List; 037 import java.util.Map; 038 import java.util.Properties; 039 import java.util.concurrent.Callable; 040 041 import javax.xml.parsers.DocumentBuilderFactory; 042 import javax.xml.transform.Transformer; 043 import javax.xml.transform.TransformerFactory; 044 import javax.xml.transform.dom.DOMSource; 045 import javax.xml.transform.stream.StreamResult; 046 047 import org.apache.oozie.BuildInfo; 048 import org.apache.oozie.client.rest.JsonTags; 049 import org.apache.oozie.client.rest.JsonToBean; 050 import org.apache.oozie.client.rest.RestConstants; 051 import org.json.simple.JSONArray; 052 import org.json.simple.JSONObject; 053 import org.json.simple.JSONValue; 054 import org.w3c.dom.Document; 055 import org.w3c.dom.Element; 056 057 /** 058 * Client API to submit and manage Oozie workflow jobs against an Oozie intance. 059 * <p/> 060 * This class is thread safe. 061 * <p/> 062 * Syntax for filter for the {@link #getJobsInfo(String)} {@link #getJobsInfo(String, int, int)} methods: 063 * <code>[NAME=VALUE][;NAME=VALUE]*</code>. 064 * <p/> 065 * Valid filter names are: 066 * <p/> 067 * <ul/> 068 * <li>name: the workflow application name from the workflow definition.</li> 069 * <li>user: the user that submitted the job.</li> 070 * <li>group: the group for the job.</li> 071 * <li>status: the status of the job.</li> 072 * </ul> 073 * <p/> 074 * 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 075 * name. Multiple values must be specified as different name value pairs. 076 */ 077 public class OozieClient { 078 079 public static final long WS_PROTOCOL_VERSION_0 = 0; 080 081 public static final long WS_PROTOCOL_VERSION = 1; 082 083 public static final String USER_NAME = "user.name"; 084 085 @Deprecated 086 public static final String GROUP_NAME = "group.name"; 087 088 public static final String JOB_ACL = "oozie.job.acl"; 089 090 public static final String APP_PATH = "oozie.wf.application.path"; 091 092 public static final String COORDINATOR_APP_PATH = "oozie.coord.application.path"; 093 094 public static final String BUNDLE_APP_PATH = "oozie.bundle.application.path"; 095 096 public static final String BUNDLE_ID = "oozie.bundle.id"; 097 098 public static final String EXTERNAL_ID = "oozie.wf.external.id"; 099 100 public static final String WORKFLOW_NOTIFICATION_URL = "oozie.wf.workflow.notification.url"; 101 102 public static final String ACTION_NOTIFICATION_URL = "oozie.wf.action.notification.url"; 103 104 public static final String COORD_ACTION_NOTIFICATION_URL = "oozie.coord.action.notification.url"; 105 106 public static final String RERUN_SKIP_NODES = "oozie.wf.rerun.skip.nodes"; 107 108 public static final String RERUN_FAIL_NODES = "oozie.wf.rerun.failnodes"; 109 110 public static final String LOG_TOKEN = "oozie.wf.log.token"; 111 112 public static final String ACTION_MAX_RETRIES = "oozie.wf.action.max.retries"; 113 114 public static final String ACTION_RETRY_INTERVAL = "oozie.wf.action.retry.interval"; 115 116 public static final String FILTER_USER = "user"; 117 118 public static final String FILTER_GROUP = "group"; 119 120 public static final String FILTER_NAME = "name"; 121 122 public static final String FILTER_STATUS = "status"; 123 124 public static final String FILTER_FREQUENCY = "frequency"; 125 126 public static final String FILTER_ID = "id"; 127 128 public static final String FILTER_UNIT = "unit"; 129 130 public static final String CHANGE_VALUE_ENDTIME = "endtime"; 131 132 public static final String CHANGE_VALUE_PAUSETIME = "pausetime"; 133 134 public static final String CHANGE_VALUE_CONCURRENCY = "concurrency"; 135 136 public static final String LIBPATH = "oozie.libpath"; 137 138 public static final String USE_SYSTEM_LIBPATH = "oozie.use.system.libpath"; 139 140 public static enum SYSTEM_MODE { 141 NORMAL, NOWEBSERVICE, SAFEMODE 142 }; 143 144 /** 145 * debugMode =0 means no debugging. > 0 means debugging on. 146 */ 147 public int debugMode = 0; 148 149 private String baseUrl; 150 private String protocolUrl; 151 private boolean validatedVersion = false; 152 private final Map<String, String> headers = new HashMap<String, String>(); 153 154 private static ThreadLocal<String> USER_NAME_TL = new ThreadLocal<String>(); 155 156 /** 157 * Allows to impersonate other users in the Oozie server. The current user 158 * must be configured as a proxyuser in Oozie. 159 * <p/> 160 * IMPORTANT: impersonation happens only with Oozie client requests done within 161 * doAs() calls. 162 * 163 * @param userName user to impersonate. 164 * @param callable callable with {@link OozieClient} calls impersonating the specified user. 165 * @return any response returned by the {@link Callable#call()} method. 166 * @throws Exception thrown by the {@link Callable#call()} method. 167 */ 168 public static <T> T doAs(String userName, Callable<T> callable) throws Exception { 169 notEmpty(userName, "userName"); 170 notNull(callable, "callable"); 171 try { 172 USER_NAME_TL.set(userName); 173 return callable.call(); 174 } 175 finally { 176 USER_NAME_TL.remove(); 177 } 178 } 179 180 protected OozieClient() { 181 } 182 183 /** 184 * Create a Workflow client instance. 185 * 186 * @param oozieUrl URL of the Oozie instance it will interact with. 187 */ 188 public OozieClient(String oozieUrl) { 189 this.baseUrl = notEmpty(oozieUrl, "oozieUrl"); 190 if (!this.baseUrl.endsWith("/")) { 191 this.baseUrl += "/"; 192 } 193 } 194 195 /** 196 * Return the Oozie URL of the workflow client instance. 197 * <p/> 198 * This URL is the base URL fo the Oozie system, with not protocol versioning. 199 * 200 * @return the Oozie URL of the workflow client instance. 201 */ 202 public String getOozieUrl() { 203 return baseUrl; 204 } 205 206 /** 207 * Return the Oozie URL used by the client and server for WS communications. 208 * <p/> 209 * This URL is the original URL plus the versioning element path. 210 * 211 * @return the Oozie URL used by the client and server for communication. 212 * @throws OozieClientException thrown in the client and the server are not protocol compatible. 213 */ 214 public String getProtocolUrl() throws OozieClientException { 215 validateWSVersion(); 216 return protocolUrl; 217 } 218 219 /** 220 * @return current debug Mode 221 */ 222 public int getDebugMode() { 223 return debugMode; 224 } 225 226 /** 227 * Set debug mode. 228 * 229 * @param debugMode : 0 means no debugging. > 0 means debugging 230 */ 231 public void setDebugMode(int debugMode) { 232 this.debugMode = debugMode; 233 } 234 235 /** 236 * Validate that the Oozie client and server instances are protocol compatible. 237 * 238 * @throws OozieClientException thrown in the client and the server are not protocol compatible. 239 */ 240 public synchronized void validateWSVersion() throws OozieClientException { 241 if (!validatedVersion) { 242 try { 243 URL url = new URL(baseUrl + RestConstants.VERSIONS); 244 HttpURLConnection conn = createConnection(url, "GET"); 245 if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { 246 JSONArray array = (JSONArray) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 247 if (array == null) { 248 throw new OozieClientException("HTTP error", "no response message"); 249 } 250 if (!array.contains(WS_PROTOCOL_VERSION) && !array.contains(WS_PROTOCOL_VERSION_0)) { 251 StringBuilder msg = new StringBuilder(); 252 msg.append("Supported version [").append(WS_PROTOCOL_VERSION).append( 253 "] or less, Unsupported versions["); 254 String separator = ""; 255 for (Object version : array) { 256 msg.append(separator).append(version); 257 } 258 msg.append("]"); 259 throw new OozieClientException(OozieClientException.UNSUPPORTED_VERSION, msg.toString()); 260 } 261 if (array.contains(WS_PROTOCOL_VERSION)) { 262 protocolUrl = baseUrl + "v" + WS_PROTOCOL_VERSION + "/"; 263 } 264 else { 265 if (array.contains(WS_PROTOCOL_VERSION_0)) { 266 protocolUrl = baseUrl + "v" + WS_PROTOCOL_VERSION_0 + "/"; 267 } 268 } 269 } 270 else { 271 handleError(conn); 272 } 273 } 274 catch (IOException ex) { 275 throw new OozieClientException(OozieClientException.IO_ERROR, ex); 276 } 277 validatedVersion = true; 278 } 279 } 280 281 /** 282 * Create an empty configuration with just the {@link #USER_NAME} set to the JVM user name. 283 * 284 * @return an empty configuration. 285 */ 286 public Properties createConfiguration() { 287 Properties conf = new Properties(); 288 String userName = USER_NAME_TL.get(); 289 if (userName == null) { 290 userName = System.getProperty("user.name"); 291 } 292 conf.setProperty(USER_NAME, userName); 293 return conf; 294 } 295 296 /** 297 * Set a HTTP header to be used in the WS requests by the workflow instance. 298 * 299 * @param name header name. 300 * @param value header value. 301 */ 302 public void setHeader(String name, String value) { 303 headers.put(notEmpty(name, "name"), notNull(value, "value")); 304 } 305 306 /** 307 * Get the value of a set HTTP header from the workflow instance. 308 * 309 * @param name header name. 310 * @return header value, <code>null</code> if not set. 311 */ 312 public String getHeader(String name) { 313 return headers.get(notEmpty(name, "name")); 314 } 315 316 /** 317 * Get the set HTTP header 318 * 319 * @return map of header key and value 320 */ 321 public Map<String, String> getHeaders() { 322 return headers; 323 } 324 325 /** 326 * Remove a HTTP header from the workflow client instance. 327 * 328 * @param name header name. 329 */ 330 public void removeHeader(String name) { 331 headers.remove(notEmpty(name, "name")); 332 } 333 334 /** 335 * Return an iterator with all the header names set in the workflow instance. 336 * 337 * @return header names. 338 */ 339 public Iterator<String> getHeaderNames() { 340 return Collections.unmodifiableMap(headers).keySet().iterator(); 341 } 342 343 private URL createURL(String collection, String resource, Map<String, String> parameters) throws IOException, 344 OozieClientException { 345 validateWSVersion(); 346 StringBuilder sb = new StringBuilder(); 347 sb.append(protocolUrl).append(collection); 348 if (resource != null && resource.length() > 0) { 349 sb.append("/").append(resource); 350 } 351 if (parameters.size() > 0) { 352 String separator = "?"; 353 for (Map.Entry<String, String> param : parameters.entrySet()) { 354 if (param.getValue() != null) { 355 sb.append(separator).append(URLEncoder.encode(param.getKey(), "UTF-8")).append("=").append( 356 URLEncoder.encode(param.getValue(), "UTF-8")); 357 separator = "&"; 358 } 359 } 360 } 361 return new URL(sb.toString()); 362 } 363 364 private boolean validateCommand(String url) { 365 { 366 if (protocolUrl.contains(baseUrl + "v0")) { 367 if (url.contains("dryrun") || url.contains("jobtype=c") || url.contains("systemmode")) { 368 return false; 369 } 370 } 371 } 372 return true; 373 } 374 375 /** 376 * Create http connection to oozie server. 377 * 378 * @param url 379 * @param method 380 * @return connection 381 * @throws IOException 382 * @throws OozieClientException 383 */ 384 protected HttpURLConnection createConnection(URL url, String method) throws IOException, OozieClientException { 385 HttpURLConnection conn = (HttpURLConnection) url.openConnection(); 386 conn.setRequestMethod(method); 387 if (method.equals("POST") || method.equals("PUT")) { 388 conn.setDoOutput(true); 389 } 390 for (Map.Entry<String, String> header : headers.entrySet()) { 391 conn.setRequestProperty(header.getKey(), header.getValue()); 392 } 393 return conn; 394 } 395 396 protected abstract class ClientCallable<T> implements Callable<T> { 397 private final String method; 398 private final String collection; 399 private final String resource; 400 private final Map<String, String> params; 401 402 public ClientCallable(String method, String collection, String resource, Map<String, String> params) { 403 this.method = method; 404 this.collection = collection; 405 this.resource = resource; 406 this.params = params; 407 } 408 409 public T call() throws OozieClientException { 410 try { 411 URL url = createURL(collection, resource, params); 412 if (validateCommand(url.toString())) { 413 if (getDebugMode() > 0) { 414 System.out.println("Connection URL:[" + url + "]"); 415 } 416 HttpURLConnection conn = createConnection(url, method); 417 return call(conn); 418 } 419 else { 420 System.out.println("Option not supported in target server. Supported only on Oozie-2.0 or greater." 421 + " Use 'oozie help' for details"); 422 throw new OozieClientException(OozieClientException.UNSUPPORTED_VERSION, new Exception()); 423 } 424 } 425 catch (IOException ex) { 426 throw new OozieClientException(OozieClientException.IO_ERROR, ex); 427 } 428 429 } 430 431 protected abstract T call(HttpURLConnection conn) throws IOException, OozieClientException; 432 } 433 434 static void handleError(HttpURLConnection conn) throws IOException, OozieClientException { 435 int status = conn.getResponseCode(); 436 String error = conn.getHeaderField(RestConstants.OOZIE_ERROR_CODE); 437 String message = conn.getHeaderField(RestConstants.OOZIE_ERROR_MESSAGE); 438 439 if (error == null) { 440 error = "HTTP error code: " + status; 441 } 442 443 if (message == null) { 444 message = conn.getResponseMessage(); 445 } 446 throw new OozieClientException(error, message); 447 } 448 449 static Map<String, String> prepareParams(String... params) { 450 Map<String, String> map = new LinkedHashMap<String, String>(); 451 for (int i = 0; i < params.length; i = i + 2) { 452 map.put(params[i], params[i + 1]); 453 } 454 String doAsUserName = USER_NAME_TL.get(); 455 if (doAsUserName != null) { 456 map.put(RestConstants.DO_AS_PARAM, doAsUserName); 457 } 458 return map; 459 } 460 461 public void writeToXml(Properties props, OutputStream out) throws IOException { 462 try { 463 Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); 464 Element conf = doc.createElement("configuration"); 465 doc.appendChild(conf); 466 conf.appendChild(doc.createTextNode("\n")); 467 for (Enumeration e = props.keys(); e.hasMoreElements();) { 468 String name = (String) e.nextElement(); 469 Object object = props.get(name); 470 String value; 471 if (object instanceof String) { 472 value = (String) object; 473 } 474 else { 475 continue; 476 } 477 Element propNode = doc.createElement("property"); 478 conf.appendChild(propNode); 479 480 Element nameNode = doc.createElement("name"); 481 nameNode.appendChild(doc.createTextNode(name.trim())); 482 propNode.appendChild(nameNode); 483 484 Element valueNode = doc.createElement("value"); 485 valueNode.appendChild(doc.createTextNode(value.trim())); 486 propNode.appendChild(valueNode); 487 488 conf.appendChild(doc.createTextNode("\n")); 489 } 490 491 DOMSource source = new DOMSource(doc); 492 StreamResult result = new StreamResult(out); 493 TransformerFactory transFactory = TransformerFactory.newInstance(); 494 Transformer transformer = transFactory.newTransformer(); 495 transformer.transform(source, result); 496 } 497 catch (Exception e) { 498 throw new IOException(e); 499 } 500 } 501 502 private class JobSubmit extends ClientCallable<String> { 503 private final Properties conf; 504 505 JobSubmit(Properties conf, boolean start) { 506 super("POST", RestConstants.JOBS, "", (start) ? prepareParams(RestConstants.ACTION_PARAM, 507 RestConstants.JOB_ACTION_START) : prepareParams()); 508 this.conf = notNull(conf, "conf"); 509 } 510 511 JobSubmit(String jobId, Properties conf) { 512 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 513 RestConstants.JOB_ACTION_RERUN)); 514 this.conf = notNull(conf, "conf"); 515 } 516 517 public JobSubmit(Properties conf, String jobActionDryrun) { 518 super("POST", RestConstants.JOBS, "", prepareParams(RestConstants.ACTION_PARAM, 519 RestConstants.JOB_ACTION_DRYRUN)); 520 this.conf = notNull(conf, "conf"); 521 } 522 523 @Override 524 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 525 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 526 writeToXml(conf, conn.getOutputStream()); 527 if (conn.getResponseCode() == HttpURLConnection.HTTP_CREATED) { 528 JSONObject json = (JSONObject) JSONValue.parse(new InputStreamReader(conn.getInputStream())); 529 return (String) json.get(JsonTags.JOB_ID); 530 } 531 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 532 handleError(conn); 533 } 534 return null; 535 } 536 } 537 538 /** 539 * Submit a workflow job. 540 * 541 * @param conf job configuration. 542 * @return the job Id. 543 * @throws OozieClientException thrown if the job could not be submitted. 544 */ 545 public String submit(Properties conf) throws OozieClientException { 546 return (new JobSubmit(conf, false)).call(); 547 } 548 549 private class JobAction extends ClientCallable<Void> { 550 551 JobAction(String jobId, String action) { 552 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, action)); 553 } 554 555 JobAction(String jobId, String action, String params) { 556 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, action, 557 RestConstants.JOB_CHANGE_VALUE, params)); 558 } 559 560 @Override 561 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 562 if (!(conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 563 handleError(conn); 564 } 565 return null; 566 } 567 } 568 569 /** 570 * dryrun for a given job 571 * 572 * @param conf Job configuration. 573 */ 574 public String dryrun(Properties conf) throws OozieClientException { 575 return new JobSubmit(conf, RestConstants.JOB_ACTION_DRYRUN).call(); 576 } 577 578 /** 579 * Start a workflow job. 580 * 581 * @param jobId job Id. 582 * @throws OozieClientException thrown if the job could not be started. 583 */ 584 public void start(String jobId) throws OozieClientException { 585 new JobAction(jobId, RestConstants.JOB_ACTION_START).call(); 586 } 587 588 /** 589 * Submit and start a workflow job. 590 * 591 * @param conf job configuration. 592 * @return the job Id. 593 * @throws OozieClientException thrown if the job could not be submitted. 594 */ 595 public String run(Properties conf) throws OozieClientException { 596 return (new JobSubmit(conf, true)).call(); 597 } 598 599 /** 600 * Rerun a workflow job. 601 * 602 * @param jobId job Id to rerun. 603 * @param conf configuration information for the rerun. 604 * @throws OozieClientException thrown if the job could not be started. 605 */ 606 public void reRun(String jobId, Properties conf) throws OozieClientException { 607 new JobSubmit(jobId, conf).call(); 608 } 609 610 /** 611 * Suspend a workflow job. 612 * 613 * @param jobId job Id. 614 * @throws OozieClientException thrown if the job could not be suspended. 615 */ 616 public void suspend(String jobId) throws OozieClientException { 617 new JobAction(jobId, RestConstants.JOB_ACTION_SUSPEND).call(); 618 } 619 620 /** 621 * Resume a workflow job. 622 * 623 * @param jobId job Id. 624 * @throws OozieClientException thrown if the job could not be resume. 625 */ 626 public void resume(String jobId) throws OozieClientException { 627 new JobAction(jobId, RestConstants.JOB_ACTION_RESUME).call(); 628 } 629 630 /** 631 * Kill a workflow job. 632 * 633 * @param jobId job Id. 634 * @throws OozieClientException thrown if the job could not be killed. 635 */ 636 public void kill(String jobId) throws OozieClientException { 637 new JobAction(jobId, RestConstants.JOB_ACTION_KILL).call(); 638 } 639 640 /** 641 * Change a coordinator job. 642 * 643 * @param jobId job Id. 644 * @param changeValue change value. 645 * @throws OozieClientException thrown if the job could not be changed. 646 */ 647 public void change(String jobId, String changeValue) throws OozieClientException { 648 new JobAction(jobId, RestConstants.JOB_ACTION_CHANGE, changeValue).call(); 649 } 650 651 private class JobInfo extends ClientCallable<WorkflowJob> { 652 653 JobInfo(String jobId, int start, int len) { 654 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 655 RestConstants.JOB_SHOW_INFO, RestConstants.OFFSET_PARAM, Integer.toString(start), 656 RestConstants.LEN_PARAM, Integer.toString(len))); 657 } 658 659 @Override 660 protected WorkflowJob call(HttpURLConnection conn) throws IOException, OozieClientException { 661 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 662 Reader reader = new InputStreamReader(conn.getInputStream()); 663 JSONObject json = (JSONObject) JSONValue.parse(reader); 664 return JsonToBean.createWorkflowJob(json); 665 } 666 else { 667 handleError(conn); 668 } 669 return null; 670 } 671 } 672 673 private class WorkflowActionInfo extends ClientCallable<WorkflowAction> { 674 WorkflowActionInfo(String actionId) { 675 super("GET", RestConstants.JOB, notEmpty(actionId, "id"), prepareParams(RestConstants.JOB_SHOW_PARAM, 676 RestConstants.JOB_SHOW_INFO)); 677 } 678 679 @Override 680 protected WorkflowAction call(HttpURLConnection conn) throws IOException, OozieClientException { 681 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 682 Reader reader = new InputStreamReader(conn.getInputStream()); 683 JSONObject json = (JSONObject) JSONValue.parse(reader); 684 return JsonToBean.createWorkflowAction(json); 685 } 686 else { 687 handleError(conn); 688 } 689 return null; 690 } 691 } 692 693 /** 694 * Get the info of a workflow job. 695 * 696 * @param jobId job Id. 697 * @return the job info. 698 * @throws OozieClientException thrown if the job info could not be retrieved. 699 */ 700 public WorkflowJob getJobInfo(String jobId) throws OozieClientException { 701 return getJobInfo(jobId, 0, 0); 702 } 703 704 /** 705 * Get the info of a workflow job and subset actions. 706 * 707 * @param jobId job Id. 708 * @param start starting index in the list of actions belonging to the job 709 * @param len number of actions to be returned 710 * @return the job info. 711 * @throws OozieClientException thrown if the job info could not be retrieved. 712 */ 713 public WorkflowJob getJobInfo(String jobId, int start, int len) throws OozieClientException { 714 return new JobInfo(jobId, start, len).call(); 715 } 716 717 /** 718 * Get the info of a workflow action. 719 * 720 * @param actionId Id. 721 * @return the workflow action info. 722 * @throws OozieClientException thrown if the job info could not be retrieved. 723 */ 724 public WorkflowAction getWorkflowActionInfo(String actionId) throws OozieClientException { 725 return new WorkflowActionInfo(actionId).call(); 726 } 727 728 /** 729 * Get the log of a workflow job. 730 * 731 * @param jobId job Id. 732 * @return the job log. 733 * @throws OozieClientException thrown if the job info could not be retrieved. 734 */ 735 public String getJobLog(String jobId) throws OozieClientException { 736 return new JobLog(jobId).call(); 737 } 738 739 /** 740 * Get the log of a job. 741 * 742 * @param jobId job Id. 743 * @param logRetrievalType Based on which filter criteria the log is retrieved 744 * @param logRetrievalScope Value for the retrieval type 745 * @param ps Printstream of command line interface 746 * @throws OozieClientException thrown if the job info could not be retrieved. 747 */ 748 public void getJobLog(String jobId, String logRetrievalType, String logRetrievalScope, PrintStream ps) 749 throws OozieClientException { 750 new JobLog(jobId, logRetrievalType, logRetrievalScope, ps).call(); 751 } 752 753 private class JobLog extends JobMetadata { 754 JobLog(String jobId) { 755 super(jobId, RestConstants.JOB_SHOW_LOG); 756 } 757 758 JobLog(String jobId, String logRetrievalType, String logRetrievalScope, PrintStream ps) { 759 super(jobId, logRetrievalType, logRetrievalScope, RestConstants.JOB_SHOW_LOG, ps); 760 } 761 } 762 763 /** 764 * Get the definition of a workflow job. 765 * 766 * @param jobId job Id. 767 * @return the job log. 768 * @throws OozieClientException thrown if the job info could not be retrieved. 769 */ 770 public String getJobDefinition(String jobId) throws OozieClientException { 771 return new JobDefinition(jobId).call(); 772 } 773 774 private class JobDefinition extends JobMetadata { 775 776 JobDefinition(String jobId) { 777 super(jobId, RestConstants.JOB_SHOW_DEFINITION); 778 } 779 } 780 781 private class JobMetadata extends ClientCallable<String> { 782 PrintStream printStream; 783 784 JobMetadata(String jobId, String metaType) { 785 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 786 metaType)); 787 } 788 789 JobMetadata(String jobId, String logRetrievalType, String logRetrievalScope, String metaType, PrintStream ps) { 790 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 791 metaType, RestConstants.JOB_LOG_TYPE_PARAM, logRetrievalType, RestConstants.JOB_LOG_SCOPE_PARAM, 792 logRetrievalScope)); 793 printStream = ps; 794 } 795 796 @Override 797 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 798 String returnVal = null; 799 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 800 InputStream is = conn.getInputStream(); 801 InputStreamReader isr = new InputStreamReader(is); 802 try { 803 if (printStream != null) { 804 sendToOutputStream(isr, -1); 805 } 806 else { 807 returnVal = getReaderAsString(isr, -1); 808 } 809 } 810 finally { 811 isr.close(); 812 } 813 } 814 else { 815 handleError(conn); 816 } 817 return returnVal; 818 } 819 820 /** 821 * Output the log to command line interface 822 * 823 * @param reader reader to read into a string. 824 * @param maxLen max content length allowed, if -1 there is no limit. 825 * @param ps Printstream of command line interface 826 * @throws IOException 827 */ 828 private void sendToOutputStream(Reader reader, int maxLen) throws IOException { 829 if (reader == null) { 830 throw new IllegalArgumentException("reader cannot be null"); 831 } 832 StringBuilder sb = new StringBuilder(); 833 char[] buffer = new char[2048]; 834 int read; 835 int count = 0; 836 int noOfCharstoFlush = 1024; 837 while ((read = reader.read(buffer)) > -1) { 838 count += read; 839 if ((maxLen > -1) && (count > maxLen)) { 840 break; 841 } 842 sb.append(buffer, 0, read); 843 if (sb.length() > noOfCharstoFlush) { 844 printStream.print(sb.toString()); 845 sb = new StringBuilder(""); 846 } 847 } 848 printStream.print(sb.toString()); 849 } 850 851 /** 852 * Return a reader as string. 853 * <p/> 854 * 855 * @param reader reader to read into a string. 856 * @param maxLen max content length allowed, if -1 there is no limit. 857 * @return the reader content. 858 * @throws IOException thrown if the resource could not be read. 859 */ 860 private String getReaderAsString(Reader reader, int maxLen) throws IOException { 861 if (reader == null) { 862 throw new IllegalArgumentException("reader cannot be null"); 863 } 864 StringBuffer sb = new StringBuffer(); 865 char[] buffer = new char[2048]; 866 int read; 867 int count = 0; 868 while ((read = reader.read(buffer)) > -1) { 869 count += read; 870 871 // read up to maxLen chars; 872 if ((maxLen > -1) && (count > maxLen)) { 873 break; 874 } 875 sb.append(buffer, 0, read); 876 } 877 reader.close(); 878 return sb.toString(); 879 } 880 } 881 882 private class CoordJobInfo extends ClientCallable<CoordinatorJob> { 883 884 CoordJobInfo(String jobId, String filter, int start, int len) { 885 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 886 RestConstants.JOB_SHOW_INFO, RestConstants.JOB_FILTER_PARAM, filter, RestConstants.OFFSET_PARAM, Integer.toString(start), 887 RestConstants.LEN_PARAM, Integer.toString(len))); 888 } 889 890 @Override 891 protected CoordinatorJob call(HttpURLConnection conn) throws IOException, OozieClientException { 892 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 893 Reader reader = new InputStreamReader(conn.getInputStream()); 894 JSONObject json = (JSONObject) JSONValue.parse(reader); 895 return JsonToBean.createCoordinatorJob(json); 896 } 897 else { 898 handleError(conn); 899 } 900 return null; 901 } 902 } 903 904 private class BundleJobInfo extends ClientCallable<BundleJob> { 905 906 BundleJobInfo(String jobId) { 907 super("GET", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.JOB_SHOW_PARAM, 908 RestConstants.JOB_SHOW_INFO)); 909 } 910 911 @Override 912 protected BundleJob call(HttpURLConnection conn) throws IOException, OozieClientException { 913 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 914 Reader reader = new InputStreamReader(conn.getInputStream()); 915 JSONObject json = (JSONObject) JSONValue.parse(reader); 916 return JsonToBean.createBundleJob(json); 917 } 918 else { 919 handleError(conn); 920 } 921 return null; 922 } 923 } 924 925 private class CoordActionInfo extends ClientCallable<CoordinatorAction> { 926 CoordActionInfo(String actionId) { 927 super("GET", RestConstants.JOB, notEmpty(actionId, "id"), prepareParams(RestConstants.JOB_SHOW_PARAM, 928 RestConstants.JOB_SHOW_INFO)); 929 } 930 931 @Override 932 protected CoordinatorAction call(HttpURLConnection conn) throws IOException, OozieClientException { 933 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 934 Reader reader = new InputStreamReader(conn.getInputStream()); 935 JSONObject json = (JSONObject) JSONValue.parse(reader); 936 return JsonToBean.createCoordinatorAction(json); 937 } 938 else { 939 handleError(conn); 940 } 941 return null; 942 } 943 } 944 945 /** 946 * Get the info of a bundle job. 947 * 948 * @param jobId job Id. 949 * @return the job info. 950 * @throws OozieClientException thrown if the job info could not be retrieved. 951 */ 952 public BundleJob getBundleJobInfo(String jobId) throws OozieClientException { 953 return new BundleJobInfo(jobId).call(); 954 } 955 956 /** 957 * Get the info of a coordinator job. 958 * 959 * @param jobId job Id. 960 * @return the job info. 961 * @throws OozieClientException thrown if the job info could not be retrieved. 962 */ 963 public CoordinatorJob getCoordJobInfo(String jobId) throws OozieClientException { 964 return new CoordJobInfo(jobId, null, 0, 0).call(); 965 } 966 967 /** 968 * Get the info of a coordinator job and subset actions. 969 * 970 * @param jobId job Id. 971 * @param filter filter the status filter 972 * @param start starting index in the list of actions belonging to the job 973 * @param len number of actions to be returned 974 * @return the job info. 975 * @throws OozieClientException thrown if the job info could not be retrieved. 976 */ 977 public CoordinatorJob getCoordJobInfo(String jobId, String filter, int start, int len) throws OozieClientException { 978 return new CoordJobInfo(jobId, filter, start, len).call(); 979 } 980 981 /** 982 * Get the info of a coordinator action. 983 * 984 * @param actionId Id. 985 * @return the coordinator action info. 986 * @throws OozieClientException thrown if the job info could not be retrieved. 987 */ 988 public CoordinatorAction getCoordActionInfo(String actionId) throws OozieClientException { 989 return new CoordActionInfo(actionId).call(); 990 } 991 992 private class JobsStatus extends ClientCallable<List<WorkflowJob>> { 993 994 JobsStatus(String filter, int start, int len) { 995 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 996 RestConstants.JOBTYPE_PARAM, "wf", RestConstants.OFFSET_PARAM, Integer.toString(start), 997 RestConstants.LEN_PARAM, Integer.toString(len))); 998 } 999 1000 @Override 1001 @SuppressWarnings("unchecked") 1002 protected List<WorkflowJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1003 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1004 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1005 Reader reader = new InputStreamReader(conn.getInputStream()); 1006 JSONObject json = (JSONObject) JSONValue.parse(reader); 1007 JSONArray workflows = (JSONArray) json.get(JsonTags.WORKFLOWS_JOBS); 1008 if (workflows == null) { 1009 workflows = new JSONArray(); 1010 } 1011 return JsonToBean.createWorkflowJobList(workflows); 1012 } 1013 else { 1014 handleError(conn); 1015 } 1016 return null; 1017 } 1018 } 1019 1020 private class CoordJobsStatus extends ClientCallable<List<CoordinatorJob>> { 1021 1022 CoordJobsStatus(String filter, int start, int len) { 1023 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 1024 RestConstants.JOBTYPE_PARAM, "coord", RestConstants.OFFSET_PARAM, Integer.toString(start), 1025 RestConstants.LEN_PARAM, Integer.toString(len))); 1026 } 1027 1028 @Override 1029 protected List<CoordinatorJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1030 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1031 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1032 Reader reader = new InputStreamReader(conn.getInputStream()); 1033 JSONObject json = (JSONObject) JSONValue.parse(reader); 1034 JSONArray jobs = (JSONArray) json.get(JsonTags.COORDINATOR_JOBS); 1035 if (jobs == null) { 1036 jobs = new JSONArray(); 1037 } 1038 return JsonToBean.createCoordinatorJobList(jobs); 1039 } 1040 else { 1041 handleError(conn); 1042 } 1043 return null; 1044 } 1045 } 1046 1047 private class BundleJobsStatus extends ClientCallable<List<BundleJob>> { 1048 1049 BundleJobsStatus(String filter, int start, int len) { 1050 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBS_FILTER_PARAM, filter, 1051 RestConstants.JOBTYPE_PARAM, "bundle", RestConstants.OFFSET_PARAM, Integer.toString(start), 1052 RestConstants.LEN_PARAM, Integer.toString(len))); 1053 } 1054 1055 @Override 1056 protected List<BundleJob> call(HttpURLConnection conn) throws IOException, OozieClientException { 1057 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1058 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1059 Reader reader = new InputStreamReader(conn.getInputStream()); 1060 JSONObject json = (JSONObject) JSONValue.parse(reader); 1061 JSONArray jobs = (JSONArray) json.get(JsonTags.BUNDLE_JOBS); 1062 if (jobs == null) { 1063 jobs = new JSONArray(); 1064 } 1065 return JsonToBean.createBundleJobList(jobs); 1066 } 1067 else { 1068 handleError(conn); 1069 } 1070 return null; 1071 } 1072 } 1073 1074 private class CoordRerun extends ClientCallable<List<CoordinatorAction>> { 1075 1076 CoordRerun(String jobId, String rerunType, String scope, boolean refresh, boolean noCleanup) { 1077 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1078 RestConstants.JOB_COORD_ACTION_RERUN, RestConstants.JOB_COORD_RERUN_TYPE_PARAM, rerunType, 1079 RestConstants.JOB_COORD_RERUN_SCOPE_PARAM, scope, RestConstants.JOB_COORD_RERUN_REFRESH_PARAM, 1080 Boolean.toString(refresh), RestConstants.JOB_COORD_RERUN_NOCLEANUP_PARAM, Boolean 1081 .toString(noCleanup))); 1082 } 1083 1084 @Override 1085 protected List<CoordinatorAction> call(HttpURLConnection conn) throws IOException, OozieClientException { 1086 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1087 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1088 Reader reader = new InputStreamReader(conn.getInputStream()); 1089 JSONObject json = (JSONObject) JSONValue.parse(reader); 1090 JSONArray coordActions = (JSONArray) json.get(JsonTags.COORDINATOR_ACTIONS); 1091 return JsonToBean.createCoordinatorActionList(coordActions); 1092 } 1093 else { 1094 handleError(conn); 1095 } 1096 return null; 1097 } 1098 } 1099 1100 private class BundleRerun extends ClientCallable<Void> { 1101 1102 BundleRerun(String jobId, String coordScope, String dateScope, boolean refresh, boolean noCleanup) { 1103 super("PUT", RestConstants.JOB, notEmpty(jobId, "jobId"), prepareParams(RestConstants.ACTION_PARAM, 1104 RestConstants.JOB_BUNDLE_ACTION_RERUN, RestConstants.JOB_BUNDLE_RERUN_COORD_SCOPE_PARAM, 1105 coordScope, RestConstants.JOB_BUNDLE_RERUN_DATE_SCOPE_PARAM, dateScope, 1106 RestConstants.JOB_COORD_RERUN_REFRESH_PARAM, Boolean.toString(refresh), 1107 RestConstants.JOB_COORD_RERUN_NOCLEANUP_PARAM, Boolean.toString(noCleanup))); 1108 } 1109 1110 @Override 1111 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1112 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1113 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1114 return null; 1115 } 1116 else { 1117 handleError(conn); 1118 } 1119 return null; 1120 } 1121 } 1122 1123 /** 1124 * Rerun coordinator actions. 1125 * 1126 * @param jobId coordinator jobId 1127 * @param rerunType rerun type 'date' if -date is used, 'action-id' if -action is used 1128 * @param scope rerun scope for date or actionIds 1129 * @param refresh true if -refresh is given in command option 1130 * @param noCleanup true if -nocleanup is given in command option 1131 * @throws OozieClientException 1132 */ 1133 public List<CoordinatorAction> reRunCoord(String jobId, String rerunType, String scope, boolean refresh, 1134 boolean noCleanup) throws OozieClientException { 1135 return new CoordRerun(jobId, rerunType, scope, refresh, noCleanup).call(); 1136 } 1137 1138 /** 1139 * Rerun bundle coordinators. 1140 * 1141 * @param jobId bundle jobId 1142 * @param coordScope rerun scope for coordinator jobs 1143 * @param dateScope rerun scope for date 1144 * @param refresh true if -refresh is given in command option 1145 * @param noCleanup true if -nocleanup is given in command option 1146 * @throws OozieClientException 1147 */ 1148 public Void reRunBundle(String jobId, String coordScope, String dateScope, boolean refresh, boolean noCleanup) 1149 throws OozieClientException { 1150 return new BundleRerun(jobId, coordScope, dateScope, refresh, noCleanup).call(); 1151 } 1152 1153 /** 1154 * Return the info of the workflow jobs that match the filter. 1155 * 1156 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1157 * @param start jobs offset, base 1. 1158 * @param len number of jobs to return. 1159 * @return a list with the workflow jobs info, without node details. 1160 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1161 */ 1162 public List<WorkflowJob> getJobsInfo(String filter, int start, int len) throws OozieClientException { 1163 return new JobsStatus(filter, start, len).call(); 1164 } 1165 1166 /** 1167 * Return the info of the workflow jobs that match the filter. 1168 * <p/> 1169 * It returns the first 100 jobs that match the filter. 1170 * 1171 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1172 * @return a list with the workflow jobs info, without node details. 1173 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1174 */ 1175 public List<WorkflowJob> getJobsInfo(String filter) throws OozieClientException { 1176 return getJobsInfo(filter, 1, 50); 1177 } 1178 1179 /** 1180 * Print sla info about coordinator and workflow jobs and actions. 1181 * 1182 * @param start starting offset 1183 * @param len number of results 1184 * @throws OozieClientException 1185 */ 1186 public void getSlaInfo(int start, int len) throws OozieClientException { 1187 new SlaInfo(start, len).call(); 1188 } 1189 1190 private class SlaInfo extends ClientCallable<Void> { 1191 1192 SlaInfo(int start, int len) { 1193 super("GET", RestConstants.SLA, "", prepareParams(RestConstants.SLA_GT_SEQUENCE_ID, 1194 Integer.toString(start), RestConstants.MAX_EVENTS, Integer.toString(len))); 1195 } 1196 1197 @Override 1198 @SuppressWarnings("unchecked") 1199 protected Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1200 conn.setRequestProperty("content-type", RestConstants.XML_CONTENT_TYPE); 1201 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1202 BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); 1203 String line = null; 1204 while ((line = br.readLine()) != null) { 1205 System.out.println(line); 1206 } 1207 } 1208 else { 1209 handleError(conn); 1210 } 1211 return null; 1212 } 1213 } 1214 1215 private class JobIdAction extends ClientCallable<String> { 1216 1217 JobIdAction(String externalId) { 1218 super("GET", RestConstants.JOBS, "", prepareParams(RestConstants.JOBTYPE_PARAM, "wf", 1219 RestConstants.JOBS_EXTERNAL_ID_PARAM, externalId)); 1220 } 1221 1222 @Override 1223 @SuppressWarnings("unchecked") 1224 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1225 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1226 Reader reader = new InputStreamReader(conn.getInputStream()); 1227 JSONObject json = (JSONObject) JSONValue.parse(reader); 1228 return (String) json.get(JsonTags.JOB_ID); 1229 } 1230 else { 1231 handleError(conn); 1232 } 1233 return null; 1234 } 1235 } 1236 1237 /** 1238 * Return the workflow job Id for an external Id. 1239 * <p/> 1240 * The external Id must have provided at job creation time. 1241 * 1242 * @param externalId external Id given at job creation time. 1243 * @return the workflow job Id for an external Id, <code>null</code> if none. 1244 * @throws OozieClientException thrown if the operation could not be done. 1245 */ 1246 public String getJobId(String externalId) throws OozieClientException { 1247 return new JobIdAction(externalId).call(); 1248 } 1249 1250 private class SetSystemMode extends ClientCallable<Void> { 1251 1252 public SetSystemMode(SYSTEM_MODE status) { 1253 super("PUT", RestConstants.ADMIN, RestConstants.ADMIN_STATUS_RESOURCE, prepareParams( 1254 RestConstants.ADMIN_SYSTEM_MODE_PARAM, status + "")); 1255 } 1256 1257 @Override 1258 public Void call(HttpURLConnection conn) throws IOException, OozieClientException { 1259 if (conn.getResponseCode() != HttpURLConnection.HTTP_OK) { 1260 handleError(conn); 1261 } 1262 return null; 1263 } 1264 } 1265 1266 /** 1267 * Enable or disable safe mode. Used by OozieCLI. In safe mode, Oozie would not accept any commands except status 1268 * command to change and view the safe mode status. 1269 * 1270 * @param status true to enable safe mode, false to disable safe mode. 1271 * @throws OozieClientException if it fails to set the safe mode status. 1272 */ 1273 public void setSystemMode(SYSTEM_MODE status) throws OozieClientException { 1274 new SetSystemMode(status).call(); 1275 } 1276 1277 private class GetSystemMode extends ClientCallable<SYSTEM_MODE> { 1278 1279 GetSystemMode() { 1280 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_STATUS_RESOURCE, prepareParams()); 1281 } 1282 1283 @Override 1284 protected SYSTEM_MODE call(HttpURLConnection conn) throws IOException, OozieClientException { 1285 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1286 Reader reader = new InputStreamReader(conn.getInputStream()); 1287 JSONObject json = (JSONObject) JSONValue.parse(reader); 1288 return SYSTEM_MODE.valueOf((String) json.get(JsonTags.OOZIE_SYSTEM_MODE)); 1289 } 1290 else { 1291 handleError(conn); 1292 } 1293 return SYSTEM_MODE.NORMAL; 1294 } 1295 } 1296 1297 /** 1298 * Returns if Oozie is in safe mode or not. 1299 * 1300 * @return true if safe mode is ON<br> 1301 * false if safe mode is OFF 1302 * @throws OozieClientException throw if it could not obtain the safe mode status. 1303 */ 1304 /* 1305 * public boolean isInSafeMode() throws OozieClientException { return new GetSafeMode().call(); } 1306 */ 1307 public SYSTEM_MODE getSystemMode() throws OozieClientException { 1308 return new GetSystemMode().call(); 1309 } 1310 1311 private class GetBuildVersion extends ClientCallable<String> { 1312 1313 GetBuildVersion() { 1314 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_BUILD_VERSION_RESOURCE, prepareParams()); 1315 } 1316 1317 @Override 1318 protected String call(HttpURLConnection conn) throws IOException, OozieClientException { 1319 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1320 Reader reader = new InputStreamReader(conn.getInputStream()); 1321 JSONObject json = (JSONObject) JSONValue.parse(reader); 1322 return (String) json.get(JsonTags.BUILD_VERSION); 1323 } 1324 else { 1325 handleError(conn); 1326 } 1327 return null; 1328 } 1329 } 1330 1331 /** 1332 * Return the Oozie server build version. 1333 * 1334 * @return the Oozie server build version. 1335 * @throws OozieClientException throw if it the server build version could not be retrieved. 1336 */ 1337 public String getServerBuildVersion() throws OozieClientException { 1338 return new GetBuildVersion().call(); 1339 } 1340 1341 /** 1342 * Return the Oozie client build version. 1343 * 1344 * @return the Oozie client build version. 1345 */ 1346 public String getClientBuildVersion() { 1347 return BuildInfo.getBuildInfo().getProperty(BuildInfo.BUILD_VERSION); 1348 } 1349 1350 /** 1351 * Return the info of the coordinator jobs that match the filter. 1352 * 1353 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1354 * @param start jobs offset, base 1. 1355 * @param len number of jobs to return. 1356 * @return a list with the coordinator jobs info 1357 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1358 */ 1359 public List<CoordinatorJob> getCoordJobsInfo(String filter, int start, int len) throws OozieClientException { 1360 return new CoordJobsStatus(filter, start, len).call(); 1361 } 1362 1363 /** 1364 * Return the info of the bundle jobs that match the filter. 1365 * 1366 * @param filter job filter. Refer to the {@link OozieClient} for the filter syntax. 1367 * @param start jobs offset, base 1. 1368 * @param len number of jobs to return. 1369 * @return a list with the bundle jobs info 1370 * @throws OozieClientException thrown if the jobs info could not be retrieved. 1371 */ 1372 public List<BundleJob> getBundleJobsInfo(String filter, int start, int len) throws OozieClientException { 1373 return new BundleJobsStatus(filter, start, len).call(); 1374 } 1375 1376 private class GetQueueDump extends ClientCallable<List<String>> { 1377 GetQueueDump() { 1378 super("GET", RestConstants.ADMIN, RestConstants.ADMIN_QUEUE_DUMP_RESOURCE, prepareParams()); 1379 } 1380 1381 @Override 1382 protected List<String> call(HttpURLConnection conn) throws IOException, OozieClientException { 1383 if ((conn.getResponseCode() == HttpURLConnection.HTTP_OK)) { 1384 Reader reader = new InputStreamReader(conn.getInputStream()); 1385 JSONObject json = (JSONObject) JSONValue.parse(reader); 1386 JSONArray queueDumpArray = (JSONArray) json.get(JsonTags.QUEUE_DUMP); 1387 1388 List<String> list = new ArrayList<String>(); 1389 list.add("[Server Queue Dump]:"); 1390 for (Object o : queueDumpArray) { 1391 JSONObject entry = (JSONObject) o; 1392 if (entry.get(JsonTags.CALLABLE_DUMP) != null) { 1393 String value = (String) entry.get(JsonTags.CALLABLE_DUMP); 1394 list.add(value); 1395 } 1396 } 1397 if (queueDumpArray.size() == 0) { 1398 list.add("Queue dump is null!"); 1399 } 1400 1401 list.add("******************************************"); 1402 list.add("[Server Uniqueness Map Dump]:"); 1403 1404 JSONArray uniqueDumpArray = (JSONArray) json.get(JsonTags.UNIQUE_MAP_DUMP); 1405 for (Object o : uniqueDumpArray) { 1406 JSONObject entry = (JSONObject) o; 1407 if (entry.get(JsonTags.UNIQUE_ENTRY_DUMP) != null) { 1408 String value = (String) entry.get(JsonTags.UNIQUE_ENTRY_DUMP); 1409 list.add(value); 1410 } 1411 } 1412 if (uniqueDumpArray.size() == 0) { 1413 list.add("Uniqueness dump is null!"); 1414 } 1415 return list; 1416 } 1417 else { 1418 handleError(conn); 1419 } 1420 return null; 1421 } 1422 } 1423 1424 /** 1425 * Return the Oozie queue's commands' dump 1426 * 1427 * @return the list of strings of callable identification in queue 1428 * @throws OozieClientException throw if it the queue dump could not be retrieved. 1429 */ 1430 public List<String> getQueueDump() throws OozieClientException { 1431 return new GetQueueDump().call(); 1432 } 1433 1434 /** 1435 * Check if the string is not null or not empty. 1436 * 1437 * @param str 1438 * @param name 1439 * @return string 1440 */ 1441 public static String notEmpty(String str, String name) { 1442 if (str == null) { 1443 throw new IllegalArgumentException(name + " cannot be null"); 1444 } 1445 if (str.length() == 0) { 1446 throw new IllegalArgumentException(name + " cannot be empty"); 1447 } 1448 return str; 1449 } 1450 1451 /** 1452 * Check if the object is not null. 1453 * 1454 * @param <T> 1455 * @param obj 1456 * @param name 1457 * @return string 1458 */ 1459 public static <T> T notNull(T obj, String name) { 1460 if (obj == null) { 1461 throw new IllegalArgumentException(name + " cannot be null"); 1462 } 1463 return obj; 1464 } 1465 1466 }