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.command.coord; 019 020 import java.io.StringReader; 021 import java.net.URI; 022 import java.util.Calendar; 023 import java.util.Date; 024 import java.util.HashMap; 025 import java.util.List; 026 import java.util.Map; 027 028 import org.apache.hadoop.conf.Configuration; 029 import org.apache.oozie.CoordinatorActionBean; 030 import org.apache.oozie.ErrorCode; 031 import org.apache.oozie.client.CoordinatorAction; 032 import org.apache.oozie.command.CommandException; 033 import org.apache.oozie.coord.CoordELEvaluator; 034 import org.apache.oozie.coord.CoordELFunctions; 035 import org.apache.oozie.coord.CoordUtils; 036 import org.apache.oozie.coord.CoordinatorJobException; 037 import org.apache.oozie.coord.SyncCoordAction; 038 import org.apache.oozie.coord.TimeUnit; 039 import org.apache.oozie.dependency.ActionDependency; 040 import org.apache.oozie.dependency.DependencyChecker; 041 import org.apache.oozie.dependency.URIHandler; 042 import org.apache.oozie.dependency.URIHandler.DependencyType; 043 import org.apache.oozie.service.Services; 044 import org.apache.oozie.service.URIHandlerService; 045 import org.apache.oozie.service.UUIDService; 046 import org.apache.oozie.util.DateUtils; 047 import org.apache.oozie.util.ELEvaluator; 048 import org.apache.oozie.util.XConfiguration; 049 import org.apache.oozie.util.XmlUtils; 050 import org.jdom.Element; 051 052 public class CoordCommandUtils { 053 public static int CURRENT = 0; 054 public static int LATEST = 1; 055 public static int FUTURE = 2; 056 public static int OFFSET = 3; 057 public static int UNEXPECTED = -1; 058 public static final String RESOLVED_UNRESOLVED_SEPARATOR = "!!"; 059 public static final String UNRESOLVED_INST_TAG = "unresolved-instances"; 060 061 /** 062 * parse a function like coord:latest(n)/future() and return the 'n'. 063 * <p/> 064 * 065 * @param function 066 * @param restArg 067 * @return int instanceNumber 068 * @throws Exception 069 */ 070 public static int getInstanceNumber(String function, StringBuilder restArg) throws Exception { 071 int funcType = getFuncType(function); 072 if (funcType == CURRENT || funcType == LATEST) { 073 return parseOneArg(function); 074 } 075 else { 076 return parseMoreArgs(function, restArg); 077 } 078 } 079 080 /** 081 * Evaluates function for coord-action-create-inst tag 082 * @param event 083 * @param appInst 084 * @param conf 085 * @param function 086 * @return evaluation result 087 * @throws Exception 088 */ 089 private static String evaluateInstanceFunction(Element event, SyncCoordAction appInst, Configuration conf, 090 String function) throws Exception { 091 ELEvaluator eval = CoordELEvaluator.createInstancesELEvaluator("coord-action-create-inst", event, appInst, conf); 092 return CoordELFunctions.evalAndWrap(eval, function); 093 } 094 095 public static int parseOneArg(String funcName) throws Exception { 096 int firstPos = funcName.indexOf("("); 097 int lastPos = funcName.lastIndexOf(")"); 098 if (firstPos >= 0 && lastPos > firstPos) { 099 String tmp = funcName.substring(firstPos + 1, lastPos).trim(); 100 if (tmp.length() > 0) { 101 return (int) Double.parseDouble(tmp); 102 } 103 } 104 throw new RuntimeException("Unformatted function :" + funcName); 105 } 106 107 private static int parseMoreArgs(String funcName, StringBuilder restArg) throws Exception { 108 int firstPos = funcName.indexOf("("); 109 int secondPos = funcName.lastIndexOf(","); 110 int lastPos = funcName.lastIndexOf(")"); 111 if (firstPos >= 0 && secondPos > firstPos) { 112 String tmp = funcName.substring(firstPos + 1, secondPos).trim(); 113 if (tmp.length() > 0) { 114 restArg.append(funcName.substring(secondPos + 1, lastPos).trim()); 115 return (int) Double.parseDouble(tmp); 116 } 117 } 118 throw new RuntimeException("Unformatted function :" + funcName); 119 } 120 121 /** 122 * @param EL function name 123 * @return type of EL function 124 */ 125 public static int getFuncType(String function) { 126 if (function.indexOf("current") >= 0) { 127 return CURRENT; 128 } 129 else if (function.indexOf("latest") >= 0) { 130 return LATEST; 131 } 132 else if (function.indexOf("future") >= 0) { 133 return FUTURE; 134 } 135 else if (function.indexOf("offset") >= 0) { 136 return OFFSET; 137 } 138 return UNEXPECTED; 139 // throw new RuntimeException("Unexpected instance name "+ function); 140 } 141 142 /** 143 * @param startInst: EL function name 144 * @param endInst: EL function name 145 * @throws CommandException if both are not the same function 146 */ 147 public static void checkIfBothSameType(String startInst, String endInst) throws CommandException { 148 if (getFuncType(startInst) != getFuncType(endInst)) { 149 throw new CommandException(ErrorCode.E1010, 150 " start-instance and end-instance both should be either latest or current or future or offset\n" 151 + " start " + startInst + " and end " + endInst); 152 } 153 } 154 155 /** 156 * Resolve list of <instance> </instance> tags. 157 * 158 * @param event 159 * @param instances 160 * @param actionInst 161 * @param conf 162 * @param eval: ELEvalautor 163 * @throws Exception 164 */ 165 public static void resolveInstances(Element event, StringBuilder instances, SyncCoordAction actionInst, 166 Configuration conf, ELEvaluator eval) throws Exception { 167 for (Element eInstance : (List<Element>) event.getChildren("instance", event.getNamespace())) { 168 if (instances.length() > 0) { 169 instances.append(CoordELFunctions.INSTANCE_SEPARATOR); 170 } 171 instances.append(materializeInstance(event, eInstance.getTextTrim(), actionInst, conf, eval)); 172 } 173 event.removeChildren("instance", event.getNamespace()); 174 } 175 176 /** 177 * Resolve <start-instance> <end-insatnce> tag. Don't resolve any 178 * latest()/future() 179 * 180 * @param event 181 * @param instances 182 * @param appInst 183 * @param conf 184 * @param eval: ELEvalautor 185 * @throws Exception 186 */ 187 public static void resolveInstanceRange(Element event, StringBuilder instances, SyncCoordAction appInst, 188 Configuration conf, ELEvaluator eval) throws Exception { 189 Element eStartInst = event.getChild("start-instance", event.getNamespace()); 190 Element eEndInst = event.getChild("end-instance", event.getNamespace()); 191 if (eStartInst != null && eEndInst != null) { 192 String strStart = evaluateInstanceFunction(event, appInst, conf, eStartInst.getTextTrim()); 193 String strEnd = evaluateInstanceFunction(event, appInst, conf, eEndInst.getTextTrim()); 194 checkIfBothSameType(strStart, strEnd); 195 StringBuilder restArg = new StringBuilder(); // To store rest 196 // arguments for 197 // future 198 // function 199 int startIndex = getInstanceNumber(strStart, restArg); 200 String startRestArg = restArg.toString(); 201 restArg.delete(0, restArg.length()); 202 int endIndex = getInstanceNumber(strEnd, restArg); 203 String endRestArg = restArg.toString(); 204 int funcType = getFuncType(strStart); 205 if (funcType == OFFSET) { 206 TimeUnit startU = TimeUnit.valueOf(startRestArg); 207 TimeUnit endU = TimeUnit.valueOf(endRestArg); 208 if (startU.getCalendarUnit() * startIndex > endU.getCalendarUnit() * endIndex) { 209 throw new CommandException(ErrorCode.E1010, 210 " start-instance should be equal or earlier than the end-instance \n" 211 + XmlUtils.prettyPrint(event)); 212 } 213 Calendar startCal = CoordELFunctions.resolveOffsetRawTime(startIndex, startU, eval); 214 Calendar endCal = CoordELFunctions.resolveOffsetRawTime(endIndex, endU, eval); 215 if (startCal != null && endCal != null) { 216 List<Integer> expandedFreqs = CoordELFunctions.expandOffsetTimes(startCal, endCal, eval); 217 for (int i = expandedFreqs.size() - 1; i >= 0; i--) { 218 String matInstance = materializeInstance(event, "${coord:offset(" + expandedFreqs.get(i) 219 + ", \"MINUTE\")}", appInst, conf, eval); 220 if (matInstance == null || matInstance.length() == 0) { 221 // Earlier than dataset's initial instance 222 break; 223 } 224 if (instances.length() > 0) { 225 instances.append(CoordELFunctions.INSTANCE_SEPARATOR); 226 } 227 instances.append(matInstance); 228 } 229 } 230 } 231 else { 232 if (startIndex > endIndex) { 233 throw new CommandException(ErrorCode.E1010, 234 " start-instance should be equal or earlier than the end-instance \n" 235 + XmlUtils.prettyPrint(event)); 236 } 237 if (funcType == CURRENT) { 238 // Everything could be resolved NOW. no latest() ELs 239 String matInstance = materializeInstance(event, "${coord:currentRange(" + startIndex + "," 240 + endIndex + ")}", appInst, conf, eval); 241 if (matInstance != null && !matInstance.isEmpty()) { 242 if (instances.length() > 0) { 243 instances.append(CoordELFunctions.INSTANCE_SEPARATOR); 244 } 245 instances.append(matInstance); 246 } 247 } 248 else { // latest(n)/future() EL is present 249 if (funcType == LATEST) { 250 instances.append("${coord:latestRange(").append(startIndex).append(",").append(endIndex) 251 .append(")}"); 252 } 253 else if (funcType == FUTURE) { 254 instances.append("${coord:futureRange(").append(startIndex).append(",").append(endIndex) 255 .append(",'").append(endRestArg).append("')}"); 256 } 257 } 258 } 259 // Remove start-instance and end-instances 260 event.removeChild("start-instance", event.getNamespace()); 261 event.removeChild("end-instance", event.getNamespace()); 262 } 263 } 264 265 /** 266 * Materialize one instance like current(-2) 267 * 268 * @param event : <data-in> 269 * @param expr : instance like current(-1) 270 * @param appInst : application specific info 271 * @param conf 272 * @param evalInst :ELEvaluator 273 * @return materialized date string 274 * @throws Exception 275 */ 276 public static String materializeInstance(Element event, String expr, SyncCoordAction appInst, Configuration conf, 277 ELEvaluator evalInst) throws Exception { 278 if (event == null) { 279 return null; 280 } 281 // ELEvaluator eval = CoordELEvaluator.createInstancesELEvaluator(event, 282 // appInst, conf); 283 return CoordELFunctions.evalAndWrap(evalInst, expr); 284 } 285 286 /** 287 * Create two new tags with <uris> and <unresolved-instances>. 288 * 289 * @param event 290 * @param instances 291 * @throws Exception 292 */ 293 private static String separateResolvedAndUnresolved(Element event, StringBuilder instances) 294 throws Exception { 295 StringBuilder unresolvedInstances = new StringBuilder(); 296 StringBuilder urisWithDoneFlag = new StringBuilder(); 297 StringBuilder depList = new StringBuilder(); 298 String uris = createEarlyURIs(event, instances.toString(), unresolvedInstances, urisWithDoneFlag); 299 if (uris.length() > 0) { 300 Element uriInstance = new Element("uris", event.getNamespace()); 301 uriInstance.addContent(uris); 302 event.getContent().add(1, uriInstance); 303 if (depList.length() > 0) { 304 depList.append(CoordELFunctions.INSTANCE_SEPARATOR); 305 } 306 depList.append(urisWithDoneFlag); 307 } 308 if (unresolvedInstances.length() > 0) { 309 Element elemInstance = new Element(UNRESOLVED_INST_TAG, event.getNamespace()); 310 elemInstance.addContent(unresolvedInstances.toString()); 311 event.getContent().add(1, elemInstance); 312 } 313 return depList.toString(); 314 } 315 316 /** 317 * The function create a list of URIs separated by "," using the instances 318 * time stamp and URI-template 319 * 320 * @param event : <data-in> event 321 * @param instances : List of time stamp separated by "," 322 * @param unresolvedInstances : list of instance with latest function 323 * @param urisWithDoneFlag : list of URIs with the done flag appended 324 * @return : list of URIs separated by ";" as a string. 325 * @throws Exception 326 */ 327 public static String createEarlyURIs(Element event, String instances, StringBuilder unresolvedInstances, 328 StringBuilder urisWithDoneFlag) throws Exception { 329 if (instances == null || instances.length() == 0) { 330 return ""; 331 } 332 String[] instanceList = instances.split(CoordELFunctions.INSTANCE_SEPARATOR); 333 StringBuilder uris = new StringBuilder(); 334 335 Element doneFlagElement = event.getChild("dataset", event.getNamespace()).getChild("done-flag", 336 event.getNamespace()); 337 URIHandlerService uriService = Services.get().get(URIHandlerService.class); 338 339 for (int i = 0; i < instanceList.length; i++) { 340 if (instanceList[i].trim().length() == 0) { 341 continue; 342 } 343 int funcType = getFuncType(instanceList[i]); 344 if (funcType == LATEST || funcType == FUTURE) { 345 if (unresolvedInstances.length() > 0) { 346 unresolvedInstances.append(CoordELFunctions.INSTANCE_SEPARATOR); 347 } 348 unresolvedInstances.append(instanceList[i]); 349 continue; 350 } 351 ELEvaluator eval = CoordELEvaluator.createURIELEvaluator(instanceList[i]); 352 if (uris.length() > 0) { 353 uris.append(CoordELFunctions.INSTANCE_SEPARATOR); 354 urisWithDoneFlag.append(CoordELFunctions.INSTANCE_SEPARATOR); 355 } 356 357 String uriPath = CoordELFunctions.evalAndWrap(eval, event.getChild("dataset", event.getNamespace()) 358 .getChild("uri-template", event.getNamespace()).getTextTrim()); 359 URIHandler uriHandler = uriService.getURIHandler(uriPath); 360 uriHandler.validate(uriPath); 361 uris.append(uriPath); 362 urisWithDoneFlag.append(uriHandler.getURIWithDoneFlag(uriPath, CoordUtils.getDoneFlag(doneFlagElement))); 363 } 364 return uris.toString(); 365 } 366 367 /** 368 * @param eSla 369 * @param nominalTime 370 * @param conf 371 * @return boolean to determine whether the SLA element is present or not 372 * @throws CoordinatorJobException 373 */ 374 public static boolean materializeSLA(Element eSla, Date nominalTime, Configuration conf) 375 throws CoordinatorJobException { 376 if (eSla == null) { 377 // eAppXml.getNamespace("sla")); 378 return false; 379 } 380 try { 381 ELEvaluator evalSla = CoordELEvaluator.createSLAEvaluator(nominalTime, conf); 382 List<Element> elemList = eSla.getChildren(); 383 for (Element elem : elemList) { 384 String updated; 385 try { 386 updated = CoordELFunctions.evalAndWrap(evalSla, elem.getText().trim()); 387 } 388 catch (Exception e) { 389 throw new CoordinatorJobException(ErrorCode.E1004, e.getMessage(), e); 390 } 391 elem.removeContent(); 392 elem.addContent(updated); 393 } 394 } 395 catch (Exception e) { 396 throw new CoordinatorJobException(ErrorCode.E1004, e.getMessage(), e); 397 } 398 return true; 399 } 400 401 /** 402 * Materialize one instance for specific nominal time. It includes: 1. 403 * Materialize data events (i.e. <data-in> and <data-out>) 2. Materialize 404 * data properties (i.e dataIn(<DS>) and dataOut(<DS>) 3. remove 'start' and 405 * 'end' tag 4. Add 'instance_number' and 'nominal-time' tag 406 * 407 * @param jobId coordinator job id 408 * @param dryrun true if it is dryrun 409 * @param eAction frequency unexploded-job 410 * @param nominalTime materialization time 411 * @param actualTime action actual time 412 * @param instanceCount instance numbers 413 * @param conf job configuration 414 * @param actionBean CoordinatorActionBean to materialize 415 * @return one materialized action for specific nominal time 416 * @throws Exception 417 */ 418 @SuppressWarnings("unchecked") 419 public static String materializeOneInstance(String jobId, boolean dryrun, Element eAction, Date nominalTime, 420 Date actualTime, int instanceCount, Configuration conf, CoordinatorActionBean actionBean) throws Exception { 421 String actionId = Services.get().get(UUIDService.class).generateChildId(jobId, instanceCount + ""); 422 SyncCoordAction appInst = new SyncCoordAction(); 423 appInst.setActionId(actionId); 424 appInst.setName(eAction.getAttributeValue("name")); 425 appInst.setNominalTime(nominalTime); 426 appInst.setActualTime(actualTime); 427 int frequency = Integer.parseInt(eAction.getAttributeValue("frequency")); 428 appInst.setFrequency(frequency); 429 appInst.setTimeUnit(TimeUnit.valueOf(eAction.getAttributeValue("freq_timeunit"))); 430 appInst.setTimeZone(DateUtils.getTimeZone(eAction.getAttributeValue("timezone"))); 431 appInst.setEndOfDuration(TimeUnit.valueOf(eAction.getAttributeValue("end_of_duration"))); 432 433 Map<String, StringBuilder> dependencyMap = null; 434 435 Element inputList = eAction.getChild("input-events", eAction.getNamespace()); 436 List<Element> dataInList = null; 437 if (inputList != null) { 438 dataInList = inputList.getChildren("data-in", eAction.getNamespace()); 439 dependencyMap = materializeDataEvents(dataInList, appInst, conf); 440 } 441 442 Element outputList = eAction.getChild("output-events", eAction.getNamespace()); 443 List<Element> dataOutList = null; 444 if (outputList != null) { 445 dataOutList = outputList.getChildren("data-out", eAction.getNamespace()); 446 materializeDataEvents(dataOutList, appInst, conf); 447 } 448 449 eAction.removeAttribute("start"); 450 eAction.removeAttribute("end"); 451 eAction.setAttribute("instance-number", Integer.toString(instanceCount)); 452 eAction.setAttribute("action-nominal-time", DateUtils.formatDateOozieTZ(nominalTime)); 453 eAction.setAttribute("action-actual-time", DateUtils.formatDateOozieTZ(actualTime)); 454 455 boolean isSla = CoordCommandUtils.materializeSLA( 456 eAction.getChild("action", eAction.getNamespace()).getChild("info", eAction.getNamespace("sla")), 457 nominalTime, conf); 458 459 // Setting up action bean 460 actionBean.setCreatedConf(XmlUtils.prettyPrint(conf).toString()); 461 actionBean.setRunConf(XmlUtils.prettyPrint(conf).toString()); 462 actionBean.setCreatedTime(actualTime); 463 actionBean.setJobId(jobId); 464 actionBean.setId(actionId); 465 actionBean.setLastModifiedTime(new Date()); 466 actionBean.setStatus(CoordinatorAction.Status.WAITING); 467 actionBean.setActionNumber(instanceCount); 468 if (dependencyMap != null) { 469 StringBuilder sbPull = dependencyMap.get(DependencyType.PULL.name()); 470 if (sbPull != null) { 471 actionBean.setMissingDependencies(sbPull.toString()); 472 } 473 StringBuilder sbPush = dependencyMap.get(DependencyType.PUSH.name()); 474 if (sbPush != null) { 475 actionBean.setPushMissingDependencies(sbPush.toString()); 476 } 477 } 478 actionBean.setNominalTime(nominalTime); 479 if (isSla == true) { 480 actionBean.setSlaXml(XmlUtils.prettyPrint( 481 eAction.getChild("action", eAction.getNamespace()).getChild("info", eAction.getNamespace("sla"))) 482 .toString()); 483 } 484 485 // actionBean.setTrackerUri(trackerUri);//TOOD: 486 // actionBean.setConsoleUrl(consoleUrl); //TODO: 487 // actionBean.setType(type);//TODO: 488 // actionBean.setErrorInfo(errorCode, errorMessage); //TODO: 489 // actionBean.setExternalStatus(externalStatus);//TODO 490 if (!dryrun) { 491 return XmlUtils.prettyPrint(eAction).toString(); 492 } 493 else { 494 return dryRunCoord(eAction, actionBean); 495 } 496 } 497 498 /** 499 * @param eAction the actionXml related element 500 * @param actionBean the coordinator action bean 501 * @return 502 * @throws Exception 503 */ 504 static String dryRunCoord(Element eAction, CoordinatorActionBean actionBean) throws Exception { 505 String action = XmlUtils.prettyPrint(eAction).toString(); 506 StringBuilder actionXml = new StringBuilder(action); 507 Configuration actionConf = new XConfiguration(new StringReader(actionBean.getRunConf())); 508 509 boolean isPushDepAvailable = true; 510 if (actionBean.getPushMissingDependencies() != null) { 511 ActionDependency actionDep = DependencyChecker.checkForAvailability( 512 actionBean.getPushMissingDependencies(), actionConf, true); 513 if (actionDep.getMissingDependencies().size() != 0) { 514 isPushDepAvailable = false; 515 } 516 517 } 518 boolean isPullDepAvailable = true; 519 CoordActionInputCheckXCommand coordActionInput = new CoordActionInputCheckXCommand(actionBean.getId(), 520 actionBean.getJobId()); 521 if (actionBean.getMissingDependencies() != null) { 522 StringBuilder existList = new StringBuilder(); 523 StringBuilder nonExistList = new StringBuilder(); 524 StringBuilder nonResolvedList = new StringBuilder(); 525 getResolvedList(actionBean.getMissingDependencies(), nonExistList, nonResolvedList); 526 isPullDepAvailable = coordActionInput.checkInput(actionXml, existList, nonExistList, actionConf); 527 } 528 529 if (isPullDepAvailable && isPushDepAvailable) { 530 // Check for latest/future 531 boolean isLatestFutureDepAvailable = coordActionInput.checkUnResolvedInput(actionXml, actionConf); 532 if (isLatestFutureDepAvailable) { 533 String newActionXml = CoordActionInputCheckXCommand.resolveCoordConfiguration(actionXml, actionConf, 534 actionBean.getId()); 535 actionXml.replace(0, actionXml.length(), newActionXml); 536 } 537 } 538 539 return actionXml.toString(); 540 } 541 542 /** 543 * Materialize all <input-events>/<data-in> or <output-events>/<data-out> 544 * tags Create uris for resolved instances. Create unresolved instance for 545 * latest()/future(). 546 * 547 * @param events 548 * @param appInst 549 * @param conf 550 * @throws Exception 551 */ 552 public static Map<String, StringBuilder> materializeDataEvents(List<Element> events, SyncCoordAction appInst, Configuration conf 553 ) throws Exception { 554 555 if (events == null) { 556 return null; 557 } 558 StringBuilder unresolvedList = new StringBuilder(); 559 Map<String, StringBuilder> dependencyMap = new HashMap<String, StringBuilder>(); 560 URIHandlerService uriService = Services.get().get(URIHandlerService.class); 561 StringBuilder pullMissingDep = null; 562 StringBuilder pushMissingDep = null; 563 564 for (Element event : events) { 565 StringBuilder instances = new StringBuilder(); 566 ELEvaluator eval = CoordELEvaluator.createInstancesELEvaluator(event, appInst, conf); 567 // Handle list of instance tag 568 resolveInstances(event, instances, appInst, conf, eval); 569 // Handle start-instance and end-instance 570 resolveInstanceRange(event, instances, appInst, conf, eval); 571 // Separate out the unresolved instances 572 String resolvedList = separateResolvedAndUnresolved(event, instances); 573 if (!resolvedList.isEmpty()) { 574 Element uri = event.getChild("dataset", event.getNamespace()).getChild("uri-template", 575 event.getNamespace()); 576 String uriTemplate = uri.getText(); 577 URI baseURI = uriService.getAuthorityWithScheme(uriTemplate); 578 URIHandler handler = uriService.getURIHandler(baseURI); 579 if (handler.getDependencyType(baseURI).equals(DependencyType.PULL)) { 580 pullMissingDep = (pullMissingDep == null) ? new StringBuilder(resolvedList) : pullMissingDep.append( 581 CoordELFunctions.INSTANCE_SEPARATOR).append(resolvedList); 582 } 583 else { 584 pushMissingDep = (pushMissingDep == null) ? new StringBuilder(resolvedList) : pushMissingDep.append( 585 CoordELFunctions.INSTANCE_SEPARATOR).append(resolvedList); 586 } 587 } 588 589 String tmpUnresolved = event.getChildTextTrim(UNRESOLVED_INST_TAG, event.getNamespace()); 590 if (tmpUnresolved != null) { 591 if (unresolvedList.length() > 0) { 592 unresolvedList.append(CoordELFunctions.INSTANCE_SEPARATOR); 593 } 594 unresolvedList.append(tmpUnresolved); 595 } 596 } 597 if (unresolvedList.length() > 0) { 598 if (pullMissingDep == null) { 599 pullMissingDep = new StringBuilder(); 600 } 601 pullMissingDep.append(RESOLVED_UNRESOLVED_SEPARATOR).append(unresolvedList); 602 } 603 dependencyMap.put(DependencyType.PULL.name(), pullMissingDep); 604 dependencyMap.put(DependencyType.PUSH.name(), pushMissingDep); 605 return dependencyMap; 606 } 607 608 /** 609 * Get resolved string from missDepList 610 * 611 * @param missDepList 612 * @param resolved 613 * @param unresolved 614 * @return resolved string 615 */ 616 public static String getResolvedList(String missDepList, StringBuilder resolved, StringBuilder unresolved) { 617 if (missDepList != null) { 618 int index = missDepList.indexOf(RESOLVED_UNRESOLVED_SEPARATOR); 619 if (index < 0) { 620 resolved.append(missDepList); 621 } 622 else { 623 resolved.append(missDepList.substring(0, index)); 624 unresolved.append(missDepList.substring(index + RESOLVED_UNRESOLVED_SEPARATOR.length())); 625 } 626 } 627 return resolved.toString(); 628 } 629 630 }