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 019package org.apache.oozie.workflow.lite; 020 021import org.apache.commons.codec.binary.Base64; 022import org.apache.commons.lang.StringUtils; 023import org.apache.hadoop.conf.Configuration; 024import org.apache.hadoop.io.Writable; 025import org.apache.oozie.ErrorCode; 026import org.apache.oozie.action.ActionExecutor; 027import org.apache.oozie.action.hadoop.FsActionExecutor; 028import org.apache.oozie.action.oozie.SubWorkflowActionExecutor; 029import org.apache.oozie.service.ActionService; 030import org.apache.oozie.service.ConfigurationService; 031import org.apache.oozie.service.SchemaService; 032import org.apache.oozie.service.Services; 033import org.apache.oozie.util.ELUtils; 034import org.apache.oozie.util.IOUtils; 035import org.apache.oozie.util.ParameterVerifier; 036import org.apache.oozie.util.ParameterVerifierException; 037import org.apache.oozie.util.WritableUtils; 038import org.apache.oozie.util.XConfiguration; 039import org.apache.oozie.util.XmlUtils; 040import org.apache.oozie.workflow.WorkflowException; 041import org.jdom.Element; 042import org.jdom.JDOMException; 043import org.jdom.Namespace; 044import org.xml.sax.SAXException; 045 046import javax.xml.transform.stream.StreamSource; 047import javax.xml.validation.Schema; 048import javax.xml.validation.Validator; 049import java.io.ByteArrayInputStream; 050import java.io.ByteArrayOutputStream; 051import java.io.DataInput; 052import java.io.DataInputStream; 053import java.io.DataOutput; 054import java.io.DataOutputStream; 055import java.io.IOException; 056import java.io.Reader; 057import java.io.StringReader; 058import java.io.StringWriter; 059import java.util.ArrayList; 060import java.util.List; 061import java.util.zip.Deflater; 062import java.util.zip.DeflaterOutputStream; 063import java.util.zip.Inflater; 064import java.util.zip.InflaterInputStream; 065 066/** 067 * Class to parse and validate workflow xml 068 */ 069public class LiteWorkflowAppParser { 070 071 private static final String LAUNCHER_E = "launcher"; 072 private static final String DECISION_E = "decision"; 073 private static final String ACTION_E = "action"; 074 private static final String END_E = "end"; 075 private static final String START_E = "start"; 076 private static final String JOIN_E = "join"; 077 private static final String FORK_E = "fork"; 078 private static final Object KILL_E = "kill"; 079 080 private static final String SLA_INFO = "info"; 081 private static final String CREDENTIALS = "credentials"; 082 private static final String GLOBAL = "global"; 083 private static final String PARAMETERS = "parameters"; 084 085 private static final String NAME_A = "name"; 086 private static final String CRED_A = "cred"; 087 private static final String USER_RETRY_MAX_A = "retry-max"; 088 private static final String USER_RETRY_INTERVAL_A = "retry-interval"; 089 private static final String TO_A = "to"; 090 private static final String USER_RETRY_POLICY_A = "retry-policy"; 091 092 private static final String FORK_PATH_E = "path"; 093 private static final String FORK_START_A = "start"; 094 095 private static final String ACTION_OK_E = "ok"; 096 private static final String ACTION_ERROR_E = "error"; 097 098 private static final String DECISION_SWITCH_E = "switch"; 099 private static final String DECISION_CASE_E = "case"; 100 private static final String DECISION_DEFAULT_E = "default"; 101 102 private static final String SUBWORKFLOW_E = "sub-workflow"; 103 104 private static final String KILL_MESSAGE_E = "message"; 105 public static final String VALIDATE_FORK_JOIN = "oozie.validate.ForkJoin"; 106 public static final String WF_VALIDATE_FORK_JOIN = "oozie.wf.validate.ForkJoin"; 107 108 public static final String DEFAULT_NAME_NODE = "oozie.actions.default.name-node"; 109 public static final String DEFAULT_JOB_TRACKER = "oozie.actions.default.job-tracker"; 110 public static final String DEFAULT_RESOURCE_MANAGER = "oozie.actions.default.resource-manager"; 111 public static final String OOZIE_GLOBAL = "oozie.wf.globalconf"; 112 113 private static final String JOB_TRACKER = "job-tracker"; 114 private static final String RESOURCE_MANAGER = "resource-manager"; 115 116 private static final String NAME_NODE = "name-node"; 117 private static final String JOB_XML = "job-xml"; 118 private static final String CONFIGURATION = "configuration"; 119 120 private Schema schema; 121 private Class<? extends ControlNodeHandler> controlNodeHandler; 122 private Class<? extends DecisionNodeHandler> decisionHandlerClass; 123 private Class<? extends ActionNodeHandler> actionHandlerClass; 124 125 private String defaultNameNode; 126 private String defaultResourceManager; 127 private String defaultJobTracker; 128 private boolean isResourceManagerTagUsed; 129 130 public LiteWorkflowAppParser(Schema schema, 131 Class<? extends ControlNodeHandler> controlNodeHandler, 132 Class<? extends DecisionNodeHandler> decisionHandlerClass, 133 Class<? extends ActionNodeHandler> actionHandlerClass) throws WorkflowException { 134 this.schema = schema; 135 this.controlNodeHandler = controlNodeHandler; 136 this.decisionHandlerClass = decisionHandlerClass; 137 this.actionHandlerClass = actionHandlerClass; 138 139 defaultNameNode = getPropertyFromConfig(DEFAULT_NAME_NODE); 140 defaultResourceManager = getPropertyFromConfig(DEFAULT_RESOURCE_MANAGER); 141 defaultJobTracker = getPropertyFromConfig(DEFAULT_JOB_TRACKER); 142 } 143 144 private String getPropertyFromConfig(final String configPropertyKey) { 145 String property = ConfigurationService.get(configPropertyKey); 146 if (property != null) { 147 property = property.trim(); 148 if (property.isEmpty()) { 149 property = null; 150 } 151 } 152 153 return property; 154 } 155 156 public LiteWorkflowApp validateAndParse(Reader reader, Configuration jobConf) throws WorkflowException { 157 return validateAndParse(reader, jobConf, null); 158 } 159 160 /** 161 * Parse and validate xml to {@link LiteWorkflowApp} 162 * 163 * @param reader 164 * @return LiteWorkflowApp 165 * @throws WorkflowException 166 */ 167 public LiteWorkflowApp validateAndParse(Reader reader, Configuration jobConf, Configuration configDefault) 168 throws WorkflowException { 169 try { 170 StringWriter writer = new StringWriter(); 171 IOUtils.copyCharStream(reader, writer); 172 String strDef = writer.toString(); 173 174 if (schema != null) { 175 Validator validator = SchemaService.getValidator(schema); 176 validator.validate(new StreamSource(new StringReader(strDef))); 177 } 178 179 Element wfDefElement = XmlUtils.parseXml(strDef); 180 ParameterVerifier.verifyParameters(jobConf, wfDefElement); 181 LiteWorkflowApp app = parse(strDef, wfDefElement, configDefault, jobConf); 182 183 184 boolean validateForkJoin = false; 185 186 if (jobConf.getBoolean(WF_VALIDATE_FORK_JOIN, true) 187 && ConfigurationService.getBoolean(VALIDATE_FORK_JOIN)) { 188 validateForkJoin = true; 189 } 190 191 LiteWorkflowValidator validator = new LiteWorkflowValidator(); 192 validator.validateWorkflow(app, validateForkJoin); 193 194 return app; 195 } 196 catch (ParameterVerifierException ex) { 197 throw new WorkflowException(ex); 198 } 199 catch (JDOMException ex) { 200 throw new WorkflowException(ErrorCode.E0700, ex.getMessage(), ex); 201 } 202 catch (SAXException ex) { 203 throw new WorkflowException(ErrorCode.E0701, ex.getMessage(), ex); 204 } 205 catch (IOException ex) { 206 throw new WorkflowException(ErrorCode.E0702, ex.getMessage(), ex); 207 } 208 } 209 210 /** 211 * Parse xml to {@link LiteWorkflowApp} 212 * 213 * @param strDef 214 * @param root 215 * @param configDefault 216 * @param jobConf 217 * @return LiteWorkflowApp 218 * @throws WorkflowException 219 */ 220 @SuppressWarnings({"unchecked"}) 221 private LiteWorkflowApp parse(String strDef, Element root, Configuration configDefault, Configuration jobConf) 222 throws WorkflowException { 223 Namespace ns = root.getNamespace(); 224 225 LiteWorkflowApp def = null; 226 GlobalSectionData gData = jobConf.get(OOZIE_GLOBAL) == null ? 227 null : getGlobalFromString(jobConf.get(OOZIE_GLOBAL)); 228 boolean serializedGlobalConf = false; 229 for (Element eNode : (List<Element>) root.getChildren()) { 230 if (eNode.getName().equals(START_E)) { 231 def = new LiteWorkflowApp(root.getAttributeValue(NAME_A), strDef, 232 new StartNodeDef(controlNodeHandler, eNode.getAttributeValue(TO_A))); 233 } else if (eNode.getName().equals(END_E)) { 234 def.addNode(new EndNodeDef(eNode.getAttributeValue(NAME_A), controlNodeHandler)); 235 } else if (eNode.getName().equals(KILL_E)) { 236 def.addNode(new KillNodeDef(eNode.getAttributeValue(NAME_A), 237 eNode.getChildText(KILL_MESSAGE_E, ns), controlNodeHandler)); 238 } else if (eNode.getName().equals(FORK_E)) { 239 List<String> paths = new ArrayList<String>(); 240 for (Element tran : (List<Element>) eNode.getChildren(FORK_PATH_E, ns)) { 241 paths.add(tran.getAttributeValue(FORK_START_A)); 242 } 243 def.addNode(new ForkNodeDef(eNode.getAttributeValue(NAME_A), controlNodeHandler, paths)); 244 } else if (eNode.getName().equals(JOIN_E)) { 245 def.addNode(new JoinNodeDef(eNode.getAttributeValue(NAME_A), controlNodeHandler, eNode.getAttributeValue(TO_A))); 246 } else if (eNode.getName().equals(DECISION_E)) { 247 Element eSwitch = eNode.getChild(DECISION_SWITCH_E, ns); 248 List<String> transitions = new ArrayList<String>(); 249 for (Element e : (List<Element>) eSwitch.getChildren(DECISION_CASE_E, ns)) { 250 transitions.add(e.getAttributeValue(TO_A)); 251 } 252 transitions.add(eSwitch.getChild(DECISION_DEFAULT_E, ns).getAttributeValue(TO_A)); 253 254 String switchStatement = XmlUtils.prettyPrint(eSwitch).toString(); 255 def.addNode(new DecisionNodeDef(eNode.getAttributeValue(NAME_A), switchStatement, decisionHandlerClass, 256 transitions)); 257 } else if (ACTION_E.equals(eNode.getName())) { 258 String[] transitions = new String[2]; 259 Element eActionConf = null; 260 for (Element elem : (List<Element>) eNode.getChildren()) { 261 if (ACTION_OK_E.equals(elem.getName())) { 262 transitions[0] = elem.getAttributeValue(TO_A); 263 } else if (ACTION_ERROR_E.equals(elem.getName())) { 264 transitions[1] = elem.getAttributeValue(TO_A); 265 } else if (SLA_INFO.equals(elem.getName()) || CREDENTIALS.equals(elem.getName())) { 266 continue; 267 } else { 268 if (!serializedGlobalConf && elem.getName().equals(SubWorkflowActionExecutor.ACTION_TYPE) && 269 elem.getChild(("propagate-configuration"), ns) != null && gData != null) { 270 serializedGlobalConf = true; 271 jobConf.set(OOZIE_GLOBAL, getGlobalString(gData)); 272 } 273 eActionConf = elem; 274 if (SUBWORKFLOW_E.equals(elem.getName())) { 275 handleDefaultsAndGlobal(gData, null, elem, ns); 276 } 277 else { 278 handleDefaultsAndGlobal(gData, configDefault, elem, ns); 279 } 280 } 281 } 282 283 String credStr = eNode.getAttributeValue(CRED_A); 284 String userRetryMaxStr = eNode.getAttributeValue(USER_RETRY_MAX_A); 285 String userRetryIntervalStr = eNode.getAttributeValue(USER_RETRY_INTERVAL_A); 286 String userRetryPolicyStr = eNode.getAttributeValue(USER_RETRY_POLICY_A); 287 try { 288 if (!StringUtils.isEmpty(userRetryMaxStr)) { 289 userRetryMaxStr = ELUtils.resolveAppName(userRetryMaxStr, jobConf); 290 } 291 if (!StringUtils.isEmpty(userRetryIntervalStr)) { 292 userRetryIntervalStr = ELUtils.resolveAppName(userRetryIntervalStr, jobConf); 293 } 294 if (!StringUtils.isEmpty(userRetryPolicyStr)) { 295 userRetryPolicyStr = ELUtils.resolveAppName(userRetryPolicyStr, jobConf); 296 } 297 } 298 catch (Exception e) { 299 throw new WorkflowException(ErrorCode.E0703, e.getMessage()); 300 } 301 302 String actionConf = XmlUtils.prettyPrint(eActionConf).toString(); 303 def.addNode(new ActionNodeDef(eNode.getAttributeValue(NAME_A), actionConf, actionHandlerClass, 304 transitions[0], transitions[1], credStr, userRetryMaxStr, userRetryIntervalStr, 305 userRetryPolicyStr)); 306 } else if (SLA_INFO.equals(eNode.getName()) || CREDENTIALS.equals(eNode.getName())) { 307 // No operation is required 308 } else if (eNode.getName().equals(GLOBAL)) { 309 if(jobConf.get(OOZIE_GLOBAL) != null) { 310 gData = getGlobalFromString(jobConf.get(OOZIE_GLOBAL)); 311 handleDefaultsAndGlobal(gData, null, eNode, ns); 312 } 313 314 gData = parseGlobalSection(ns, eNode); 315 316 } else if (eNode.getName().equals(PARAMETERS)) { 317 // No operation is required 318 } else { 319 throw new WorkflowException(ErrorCode.E0703, eNode.getName()); 320 } 321 } 322 return def; 323 } 324 325 /** 326 * Read the GlobalSectionData from Base64 string. 327 * @param globalStr 328 * @return GlobalSectionData 329 * @throws WorkflowException 330 */ 331 private GlobalSectionData getGlobalFromString(String globalStr) throws WorkflowException { 332 GlobalSectionData globalSectionData = new GlobalSectionData(); 333 try { 334 byte[] data = Base64.decodeBase64(globalStr); 335 Inflater inflater = new Inflater(); 336 DataInputStream ois = new DataInputStream(new InflaterInputStream(new ByteArrayInputStream(data), inflater)); 337 globalSectionData.readFields(ois); 338 ois.close(); 339 } catch (Exception ex) { 340 throw new WorkflowException(ErrorCode.E0700, "Error while processing global section conf"); 341 } 342 return globalSectionData; 343 } 344 345 346 /** 347 * Write the GlobalSectionData to a Base64 string. 348 * @param globalSectionData 349 * @return String 350 * @throws WorkflowException 351 */ 352 private String getGlobalString(GlobalSectionData globalSectionData) throws WorkflowException { 353 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 354 DataOutputStream oos = null; 355 try { 356 Deflater def = new Deflater(); 357 oos = new DataOutputStream(new DeflaterOutputStream(baos, def)); 358 globalSectionData.write(oos); 359 oos.close(); 360 } catch (IOException e) { 361 throw new WorkflowException(ErrorCode.E0700, "Error while processing global section conf"); 362 } 363 return Base64.encodeBase64String(baos.toByteArray()); 364 } 365 366 private void addChildElement(Element parent, Namespace ns, String childName, String childValue) { 367 Element child = new Element(childName, ns); 368 child.setText(childValue); 369 parent.addContent(child); 370 } 371 372 private class GlobalSectionData implements Writable { 373 String jobTracker; 374 String nameNode; 375 List<String> jobXmls; 376 Configuration conf; 377 378 public GlobalSectionData() { 379 } 380 381 public GlobalSectionData(String jobTracker, String nameNode, List<String> jobXmls, Configuration conf) { 382 this.jobTracker = jobTracker; 383 this.nameNode = nameNode; 384 this.jobXmls = jobXmls; 385 this.conf = conf; 386 } 387 388 @Override 389 public void write(DataOutput dataOutput) throws IOException { 390 WritableUtils.writeStr(dataOutput, jobTracker); 391 WritableUtils.writeStr(dataOutput, nameNode); 392 393 if(jobXmls != null && !jobXmls.isEmpty()) { 394 dataOutput.writeInt(jobXmls.size()); 395 for (String content : jobXmls) { 396 WritableUtils.writeStr(dataOutput, content); 397 } 398 } else { 399 dataOutput.writeInt(0); 400 } 401 if(conf != null) { 402 WritableUtils.writeStr(dataOutput, XmlUtils.prettyPrint(conf).toString()); 403 } else { 404 WritableUtils.writeStr(dataOutput, null); 405 } 406 } 407 408 @Override 409 public void readFields(DataInput dataInput) throws IOException { 410 jobTracker = WritableUtils.readStr(dataInput); 411 nameNode = WritableUtils.readStr(dataInput); 412 int length = dataInput.readInt(); 413 if (length > 0) { 414 jobXmls = new ArrayList<String>(); 415 for (int i = 0; i < length; i++) { 416 jobXmls.add(WritableUtils.readStr(dataInput)); 417 } 418 } 419 String confString = WritableUtils.readStr(dataInput); 420 if(confString != null) { 421 conf = new XConfiguration(new StringReader(confString)); 422 } 423 } 424 } 425 426 private GlobalSectionData parseGlobalSection(Namespace ns, Element global) throws WorkflowException { 427 GlobalSectionData gData = null; 428 if (global != null) { 429 String globalJobTracker = null; 430 Element globalJobTrackerElement = getResourceManager(ns, global); 431 isResourceManagerTagUsed = globalJobTrackerElement != null 432 && globalJobTrackerElement.getName().equals(RESOURCE_MANAGER); 433 if (globalJobTrackerElement != null) { 434 globalJobTracker = globalJobTrackerElement.getValue(); 435 } 436 437 438 String globalNameNode = null; 439 Element globalNameNodeElement = global.getChild(NAME_NODE, ns); 440 if (globalNameNodeElement != null) { 441 globalNameNode = globalNameNodeElement.getValue(); 442 } 443 444 List<String> globalJobXmls = null; 445 @SuppressWarnings("unchecked") 446 List<Element> globalJobXmlElements = global.getChildren(JOB_XML, ns); 447 if (!globalJobXmlElements.isEmpty()) { 448 globalJobXmls = new ArrayList<String>(globalJobXmlElements.size()); 449 for(Element jobXmlElement: globalJobXmlElements) { 450 globalJobXmls.add(jobXmlElement.getText()); 451 } 452 } 453 454 Configuration globalConf = new XConfiguration(); 455 Element globalConfigurationElement = global.getChild(CONFIGURATION, ns); 456 if (globalConfigurationElement != null) { 457 try { 458 globalConf = new XConfiguration(new StringReader(XmlUtils.prettyPrint(globalConfigurationElement).toString())); 459 } catch (IOException ioe) { 460 throw new WorkflowException(ErrorCode.E0700, "Error while processing global section conf"); 461 } 462 } 463 464 Element globalLauncherElement = global.getChild(LAUNCHER_E, ns); 465 if (globalLauncherElement != null) { 466 LauncherConfigHandler launcherConfigHandler = new LauncherConfigHandler(globalConf, globalLauncherElement, ns); 467 launcherConfigHandler.processSettings(); 468 } 469 gData = new GlobalSectionData(globalJobTracker, globalNameNode, globalJobXmls, globalConf); 470 } 471 return gData; 472 } 473 474 private Element getResourceManager(final Namespace ns, final Element element) { 475 final Element resourceManager = element.getChild(RESOURCE_MANAGER, ns); 476 if (resourceManager != null) { 477 return resourceManager; 478 } 479 return element.getChild(JOB_TRACKER, ns); 480 } 481 482 private void handleDefaultsAndGlobal(GlobalSectionData gData, Configuration configDefault, Element actionElement, Namespace ns) 483 throws WorkflowException { 484 485 ActionExecutor ae = Services.get().get(ActionService.class).getExecutor(actionElement.getName()); 486 if (ae == null && !GLOBAL.equals(actionElement.getName())) { 487 throw new WorkflowException(ErrorCode.E0723, actionElement.getName(), ActionService.class.getName()); 488 } 489 490 Namespace actionNs = actionElement.getNamespace(); 491 492 // If this is the global section or ActionExecutor.requiresNameNodeJobTracker() returns true, we parse the action's 493 // <name-node> and <job-tracker> fields. If those aren't defined, we take them from the <global> section. If those 494 // aren't defined, we take them from the oozie-site defaults. If those aren't defined, we throw a WorkflowException. 495 // However, for the SubWorkflow and FS Actions, as well as the <global> section, we don't throw the WorkflowException. 496 // Also, we only parse the NN (not the JT) for the FS Action. 497 if (SubWorkflowActionExecutor.ACTION_TYPE.equals(actionElement.getName()) || 498 FsActionExecutor.ACTION_TYPE.equals(actionElement.getName()) || 499 GLOBAL.equals(actionElement.getName()) || ae.requiresNameNodeJobTracker()) { 500 if (actionElement.getChild(NAME_NODE, actionNs) == null) { 501 if (gData != null && gData.nameNode != null) { 502 addChildElement(actionElement, actionNs, NAME_NODE, gData.nameNode); 503 } else if (defaultNameNode != null) { 504 addChildElement(actionElement, actionNs, NAME_NODE, defaultNameNode); 505 } else if (!(SubWorkflowActionExecutor.ACTION_TYPE.equals(actionElement.getName()) || 506 FsActionExecutor.ACTION_TYPE.equals(actionElement.getName()) || 507 GLOBAL.equals(actionElement.getName()))) { 508 throw new WorkflowException(ErrorCode.E0701, "No " + NAME_NODE + " defined"); 509 } 510 } 511 if (getResourceManager(actionNs, actionElement) == null && 512 !FsActionExecutor.ACTION_TYPE.equals(actionElement.getName())) { 513 if (gData != null && gData.jobTracker != null) { 514 addResourceManagerOrJobTracker(actionElement, actionNs, gData.jobTracker, isResourceManagerTagUsed); 515 } else if (defaultResourceManager != null) { 516 addResourceManagerOrJobTracker(actionElement, actionNs, defaultResourceManager, true); 517 } else if (defaultJobTracker != null) { 518 addResourceManagerOrJobTracker(actionElement, actionNs, defaultJobTracker, false); 519 } else if (!(SubWorkflowActionExecutor.ACTION_TYPE.equals(actionElement.getName()) || 520 GLOBAL.equals(actionElement.getName()))) { 521 throw new WorkflowException(ErrorCode.E0701, "No " + JOB_TRACKER + " or " + RESOURCE_MANAGER + " defined"); 522 } 523 } 524 } 525 526 // If this is the global section or ActionExecutor.supportsConfigurationJobXML() returns true, we parse the action's 527 // <configuration> and <job-xml> fields. We also merge this with those from the <global> section, if given. If none are 528 // defined, empty values are placed. Exceptions are thrown if there's an error parsing, but not if they're not given. 529 if (GLOBAL.equals(actionElement.getName()) || ae.supportsConfigurationJobXML()) { 530 @SuppressWarnings("unchecked") 531 List<Element> actionJobXmls = actionElement.getChildren(JOB_XML, actionNs); 532 if (gData != null && gData.jobXmls != null) { 533 for(String gJobXml : gData.jobXmls) { 534 boolean alreadyExists = false; 535 for (Element actionXml : actionJobXmls) { 536 if (gJobXml.equals(actionXml.getText())) { 537 alreadyExists = true; 538 break; 539 } 540 } 541 if (!alreadyExists) { 542 Element ejobXml = new Element(JOB_XML, actionNs); 543 ejobXml.setText(gJobXml); 544 actionElement.addContent(ejobXml); 545 } 546 } 547 } 548 549 try { 550 XConfiguration actionConf = new XConfiguration(); 551 if (configDefault != null) 552 XConfiguration.copy(configDefault, actionConf); 553 if (gData != null && gData.conf != null) { 554 XConfiguration.copy(gData.conf, actionConf); 555 } 556 557 Element launcherConfiguration = actionElement.getChild(LAUNCHER_E, actionNs); 558 if (launcherConfiguration != null) { 559 LauncherConfigHandler launcherConfigHandler = new LauncherConfigHandler( 560 actionConf, launcherConfiguration, actionNs); 561 launcherConfigHandler.processSettings(); 562 } 563 564 Element actionConfiguration = actionElement.getChild(CONFIGURATION, actionNs); 565 if (actionConfiguration != null) { 566 //copy and override 567 XConfiguration.copy(new XConfiguration(new StringReader(XmlUtils.prettyPrint(actionConfiguration).toString())), 568 actionConf); 569 } 570 571 int position = actionElement.indexOf(actionConfiguration); 572 actionElement.removeContent(actionConfiguration); //replace with enhanced one 573 Element eConfXml = XmlUtils.parseXml(actionConf.toXmlString(false)); 574 eConfXml.detach(); 575 eConfXml.setNamespace(actionNs); 576 if (position > 0) { 577 actionElement.addContent(position, eConfXml); 578 } 579 else { 580 actionElement.addContent(eConfXml); 581 } 582 } 583 catch (IOException e) { 584 throw new WorkflowException(ErrorCode.E0700, "Error while processing action conf"); 585 } 586 catch (JDOMException e) { 587 throw new WorkflowException(ErrorCode.E0700, "Error while processing action conf"); 588 } 589 } 590 } 591 592 private void addResourceManagerOrJobTracker(final Element actionElement, final Namespace actionNs, final String jobTracker, 593 boolean isResourceManagerUsed) { 594 if (isResourceManagerUsed) { 595 addChildElement(actionElement, actionNs, RESOURCE_MANAGER, jobTracker); 596 } else { 597 addChildElement(actionElement, actionNs, JOB_TRACKER, jobTracker); 598 } 599 } 600 601 private void addResourceManager(final Element actionElement, final Namespace actionNs, final String jobTracker) { 602 addChildElement(actionElement, actionNs, RESOURCE_MANAGER, jobTracker); 603 } 604}