001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.impl; 018 019import java.io.File; 020import java.io.FileInputStream; 021import java.io.IOException; 022import java.io.InputStream; 023import java.util.ArrayList; 024import java.util.HashSet; 025import java.util.LinkedHashMap; 026import java.util.List; 027import java.util.Map; 028import java.util.Set; 029import java.util.concurrent.atomic.AtomicInteger; 030 031import org.apache.camel.CamelContext; 032import org.apache.camel.CamelContextAware; 033import org.apache.camel.NamedNode; 034import org.apache.camel.model.Model; 035import org.apache.camel.model.RouteConfigurationDefinition; 036import org.apache.camel.model.RouteConfigurationsDefinition; 037import org.apache.camel.model.RouteDefinition; 038import org.apache.camel.model.RouteTemplateDefinition; 039import org.apache.camel.model.RouteTemplatesDefinition; 040import org.apache.camel.model.RoutesDefinition; 041import org.apache.camel.model.app.RegistryBeanDefinition; 042import org.apache.camel.model.rest.RestDefinition; 043import org.apache.camel.model.rest.RestsDefinition; 044import org.apache.camel.spi.DumpRoutesStrategy; 045import org.apache.camel.spi.ModelToXMLDumper; 046import org.apache.camel.spi.ModelToYAMLDumper; 047import org.apache.camel.spi.Resource; 048import org.apache.camel.spi.annotations.ServiceFactory; 049import org.apache.camel.support.PluginHelper; 050import org.apache.camel.support.ResourceSupport; 051import org.apache.camel.support.service.ServiceSupport; 052import org.apache.camel.util.FileUtil; 053import org.apache.camel.util.IOHelper; 054import org.apache.camel.util.StringHelper; 055import org.slf4j.Logger; 056import org.slf4j.LoggerFactory; 057 058import static org.apache.camel.support.LoggerHelper.stripSourceLocationLineNumber; 059 060/** 061 * Default {@link DumpRoutesStrategy} that dumps the routes to standard logger. 062 */ 063@ServiceFactory("default-" + DumpRoutesStrategy.FACTORY) 064public class DefaultDumpRoutesStrategy extends ServiceSupport implements DumpRoutesStrategy, CamelContextAware { 065 066 private static final Logger LOG = LoggerFactory.getLogger(DefaultDumpRoutesStrategy.class); 067 private static final String DIVIDER = "--------------------------------------------------------------------------------"; 068 069 private final AtomicInteger counter = new AtomicInteger(); 070 private CamelContext camelContext; 071 072 private String include = "routes"; 073 private boolean resolvePlaceholders = true; 074 private boolean uriAsParameters; 075 private boolean generatedIds = true; 076 private boolean log = true; 077 private String output; 078 private String outputFileName; 079 080 @Override 081 public CamelContext getCamelContext() { 082 return camelContext; 083 } 084 085 @Override 086 public void setCamelContext(CamelContext camelContext) { 087 this.camelContext = camelContext; 088 } 089 090 @Override 091 protected void doStart() throws Exception { 092 // output can be a filename, dir, or both 093 String name = FileUtil.stripPath(output); 094 if (name != null && name.contains(".")) { 095 outputFileName = name; 096 output = FileUtil.onlyPath(output); 097 if (output == null || output.isEmpty()) { 098 output = "."; 099 } 100 } 101 } 102 103 public String getInclude() { 104 return include; 105 } 106 107 public void setInclude(String include) { 108 this.include = include; 109 } 110 111 public boolean isResolvePlaceholders() { 112 return resolvePlaceholders; 113 } 114 115 public void setResolvePlaceholders(boolean resolvePlaceholders) { 116 this.resolvePlaceholders = resolvePlaceholders; 117 } 118 119 public boolean isGeneratedIds() { 120 return generatedIds; 121 } 122 123 public void setGeneratedIds(boolean generatedIds) { 124 this.generatedIds = generatedIds; 125 } 126 127 public boolean isLog() { 128 return log; 129 } 130 131 public void setLog(boolean log) { 132 this.log = log; 133 } 134 135 public String getOutput() { 136 return output; 137 } 138 139 public void setOutput(String output) { 140 this.output = output; 141 } 142 143 public boolean isUriAsParameters() { 144 return uriAsParameters; 145 } 146 147 public void setUriAsParameters(boolean uriAsParameters) { 148 this.uriAsParameters = uriAsParameters; 149 } 150 151 @Override 152 public void dumpRoutes(String format) { 153 if ("yaml".equalsIgnoreCase(format)) { 154 doDumpRoutesAsYaml(camelContext); 155 } else if ("xml".equalsIgnoreCase(format)) { 156 doDumpRoutesAsXml(camelContext); 157 } 158 } 159 160 protected void doDumpRoutesAsYaml(CamelContext camelContext) { 161 final ModelToYAMLDumper dumper = PluginHelper.getModelToYAMLDumper(camelContext); 162 final Model model = camelContext.getCamelContextExtension().getContextPlugin(Model.class); 163 final DummyResource dummy = new DummyResource(null, null); 164 final Set<String> files = new HashSet<>(); 165 166 if (include.contains("*") || include.contains("all") || include.contains("beans")) { 167 int size = model.getRegistryBeans().size(); 168 if (size > 0) { 169 Map<Resource, List<RegistryBeanDefinition>> groups = new LinkedHashMap<>(); 170 for (RegistryBeanDefinition bean : model.getRegistryBeans()) { 171 Resource res = bean.getResource(); 172 if (res == null) { 173 res = dummy; 174 } 175 List<RegistryBeanDefinition> beans = groups.computeIfAbsent(res, resource -> new ArrayList<>()); 176 beans.add(bean); 177 } 178 StringBuilder sbLog = new StringBuilder(); 179 for (Map.Entry<Resource, List<RegistryBeanDefinition>> entry : groups.entrySet()) { 180 List<RegistryBeanDefinition> beans = entry.getValue(); 181 Resource resource = entry.getKey(); 182 183 StringBuilder sbLocal = new StringBuilder(); 184 doDumpYamlBeans(camelContext, beans, resource == dummy ? null : resource, dumper, "beans", sbLocal, sbLog); 185 // dump each resource into its own file 186 doDumpToDirectory(resource, sbLocal, "beans", "yaml", files); 187 } 188 if (!sbLog.isEmpty() && log) { 189 LOG.info("Dumping {} beans as YAML", size); 190 LOG.info("{}", sbLog); 191 } 192 } 193 } 194 195 if (include.contains("*") || include.contains("all") || include.contains("routes")) { 196 int size = model.getRouteDefinitions().size(); 197 if (size > 0) { 198 Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>(); 199 for (RouteDefinition route : model.getRouteDefinitions()) { 200 if ((route.isRest() != null && route.isRest()) || (route.isTemplate() != null && route.isTemplate())) { 201 // skip routes that are rest/templates 202 continue; 203 } 204 Resource res = route.getResource(); 205 if (res == null) { 206 res = dummy; 207 } 208 RoutesDefinition routes = groups.computeIfAbsent(res, resource -> new RoutesDefinition()); 209 routes.getRoutes().add(route); 210 } 211 StringBuilder sbLog = new StringBuilder(); 212 for (Map.Entry<Resource, RoutesDefinition> entry : groups.entrySet()) { 213 RoutesDefinition def = entry.getValue(); 214 Resource resource = entry.getKey(); 215 216 StringBuilder sbLocal = new StringBuilder(); 217 doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "routes", sbLocal, sbLog); 218 // dump each resource into its own file 219 doDumpToDirectory(resource, sbLocal, "routes", "yaml", files); 220 } 221 if (!sbLog.isEmpty() && log) { 222 LOG.info("Dumping {} routes as YAML", size); 223 LOG.info("{}", sbLog); 224 } 225 } 226 } 227 228 if (include.contains("*") || include.contains("all") || include.contains("routeConfigurations") 229 || include.contains("route-configurations")) { 230 int size = model.getRouteConfigurationDefinitions().size(); 231 if (size > 0) { 232 Map<Resource, RouteConfigurationsDefinition> groups = new LinkedHashMap<>(); 233 for (RouteConfigurationDefinition config : model.getRouteConfigurationDefinitions()) { 234 Resource res = config.getResource(); 235 if (res == null) { 236 res = dummy; 237 } 238 RouteConfigurationsDefinition routes 239 = groups.computeIfAbsent(res, resource -> new RouteConfigurationsDefinition()); 240 routes.getRouteConfigurations().add(config); 241 } 242 StringBuilder sbLog = new StringBuilder(); 243 for (Map.Entry<Resource, RouteConfigurationsDefinition> entry : groups.entrySet()) { 244 RouteConfigurationsDefinition def = entry.getValue(); 245 Resource resource = entry.getKey(); 246 247 StringBuilder sbLocal = new StringBuilder(); 248 doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "route-configurations", sbLocal, 249 sbLog); 250 // dump each resource into its own file 251 doDumpToDirectory(resource, sbLocal, "route-configurations", "yaml", files); 252 } 253 if (!sbLog.isEmpty() && log) { 254 LOG.info("Dumping {} route-configurations as YAML", size); 255 LOG.info("{}", sbLog); 256 } 257 } 258 } 259 260 if (include.contains("*") || include.contains("all") || include.contains("rests")) { 261 int size = model.getRestDefinitions().size(); 262 if (size > 0) { 263 Map<Resource, RestsDefinition> groups = new LinkedHashMap<>(); 264 for (RestDefinition rest : model.getRestDefinitions()) { 265 Resource res = rest.getResource(); 266 if (res == null) { 267 res = dummy; 268 } 269 RestsDefinition rests = groups.computeIfAbsent(res, resource -> new RestsDefinition()); 270 rests.getRests().add(rest); 271 } 272 StringBuilder sbLog = new StringBuilder(); 273 for (Map.Entry<Resource, RestsDefinition> entry : groups.entrySet()) { 274 RestsDefinition def = entry.getValue(); 275 Resource resource = entry.getKey(); 276 277 StringBuilder sbLocal = new StringBuilder(); 278 doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "rests", sbLocal, sbLog); 279 // dump each resource into its own file 280 doDumpToDirectory(resource, sbLocal, "rests", "yaml", files); 281 } 282 if (!sbLog.isEmpty() && log) { 283 LOG.info("Dumping {} rests as YAML", size); 284 LOG.info("{}", sbLog); 285 } 286 } 287 } 288 289 if (include.contains("*") || include.contains("all") || include.contains("routeTemplates") 290 || include.contains("route-templates")) { 291 int size = model.getRouteTemplateDefinitions().size(); 292 if (size > 0) { 293 Map<Resource, RouteTemplatesDefinition> groups = new LinkedHashMap<>(); 294 for (RouteTemplateDefinition rt : model.getRouteTemplateDefinitions()) { 295 Resource res = rt.getResource(); 296 if (res == null) { 297 res = dummy; 298 } 299 RouteTemplatesDefinition rests = groups.computeIfAbsent(res, resource -> new RouteTemplatesDefinition()); 300 rests.getRouteTemplates().add(rt); 301 } 302 StringBuilder sbLog = new StringBuilder(); 303 for (Map.Entry<Resource, RouteTemplatesDefinition> entry : groups.entrySet()) { 304 RouteTemplatesDefinition def = entry.getValue(); 305 Resource resource = entry.getKey(); 306 307 StringBuilder sbLocal = new StringBuilder(); 308 doDumpYaml(camelContext, def, resource == dummy ? null : resource, dumper, "route-templates", sbLocal, 309 sbLog); 310 // dump each resource into its own file 311 doDumpToDirectory(resource, sbLocal, "route-templates", "yaml", files); 312 } 313 if (!sbLog.isEmpty() && log) { 314 LOG.info("Dumping {} route-templates as YAML", size); 315 LOG.info("{}", sbLog); 316 } 317 } 318 } 319 } 320 321 protected void doDumpYaml( 322 CamelContext camelContext, NamedNode def, Resource resource, 323 ModelToYAMLDumper dumper, String kind, StringBuilder sbLocal, StringBuilder sbLog) { 324 try { 325 String dump = dumper.dumpModelAsYaml(camelContext, def, resolvePlaceholders, uriAsParameters, generatedIds); 326 sbLocal.append(dump); 327 appendLogDump(resource, dump, sbLog); 328 } catch (Exception e) { 329 LOG.warn("Error dumping {}} to YAML due to {}. This exception is ignored.", kind, e.getMessage(), e); 330 } 331 } 332 333 protected void doDumpYamlBeans( 334 CamelContext camelContext, List beans, Resource resource, 335 ModelToYAMLDumper dumper, String kind, StringBuilder sbLocal, StringBuilder sbLog) { 336 try { 337 String dump = dumper.dumpBeansAsYaml(camelContext, beans); 338 sbLocal.append(dump); 339 appendLogDump(resource, dump, sbLog); 340 } catch (Exception e) { 341 LOG.warn("Error dumping {}} to YAML due to {}. This exception is ignored.", kind, e.getMessage(), e); 342 } 343 } 344 345 protected void doDumpRoutesAsXml(CamelContext camelContext) { 346 final ModelToXMLDumper dumper = PluginHelper.getModelToXMLDumper(camelContext); 347 final Model model = camelContext.getCamelContextExtension().getContextPlugin(Model.class); 348 final DummyResource dummy = new DummyResource(null, null); 349 final Set<String> files = new HashSet<>(); 350 351 if (include.contains("*") || include.contains("all") || include.contains("beans")) { 352 int size = model.getRegistryBeans().size(); 353 if (size > 0) { 354 Map<Resource, List<RegistryBeanDefinition>> groups = new LinkedHashMap<>(); 355 for (RegistryBeanDefinition bean : model.getRegistryBeans()) { 356 Resource res = bean.getResource(); 357 if (res == null) { 358 res = dummy; 359 } 360 List<RegistryBeanDefinition> beans = groups.computeIfAbsent(res, resource -> new ArrayList<>()); 361 beans.add(bean); 362 } 363 StringBuilder sbLog = new StringBuilder(); 364 for (Map.Entry<Resource, List<RegistryBeanDefinition>> entry : groups.entrySet()) { 365 List<RegistryBeanDefinition> beans = entry.getValue(); 366 Resource resource = entry.getKey(); 367 368 StringBuilder sbLocal = new StringBuilder(); 369 doDumpXmlBeans(camelContext, beans, resource == dummy ? null : resource, dumper, "beans", sbLocal, sbLog); 370 // dump each resource into its own file 371 doDumpToDirectory(resource, sbLocal, "beans", "xml", files); 372 } 373 if (!sbLog.isEmpty() && log) { 374 LOG.info("Dumping {} beans as XML", size); 375 LOG.info("{}", sbLog); 376 } 377 } 378 } 379 380 if (include.contains("*") || include.contains("all") || include.contains("routes")) { 381 int size = model.getRouteDefinitions().size(); 382 if (size > 0) { 383 Map<Resource, RoutesDefinition> groups = new LinkedHashMap<>(); 384 for (RouteDefinition route : model.getRouteDefinitions()) { 385 if ((route.isRest() != null && route.isRest()) || (route.isTemplate() != null && route.isTemplate())) { 386 // skip routes that are rest/templates 387 continue; 388 } 389 Resource res = route.getResource(); 390 if (res == null) { 391 res = dummy; 392 } 393 RoutesDefinition routes = groups.computeIfAbsent(res, resource -> new RoutesDefinition()); 394 routes.getRoutes().add(route); 395 } 396 StringBuilder sbLog = new StringBuilder(); 397 for (Map.Entry<Resource, RoutesDefinition> entry : groups.entrySet()) { 398 RoutesDefinition def = entry.getValue(); 399 Resource resource = entry.getKey(); 400 401 StringBuilder sbLocal = new StringBuilder(); 402 doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "route", "routes", sbLocal, 403 sbLog); 404 // dump each resource into its own file 405 doDumpToDirectory(resource, sbLocal, "routes", "xml", files); 406 } 407 if (!sbLog.isEmpty() && log) { 408 LOG.info("Dumping {} routes as XML", size); 409 LOG.info("{}", sbLog); 410 } 411 } 412 } 413 414 if (include.contains("*") || include.contains("all") || include.contains("routeConfigurations") 415 || include.contains("route-configurations")) { 416 int size = model.getRouteConfigurationDefinitions().size(); 417 if (size > 0) { 418 Map<Resource, RouteConfigurationsDefinition> groups = new LinkedHashMap<>(); 419 for (RouteConfigurationDefinition config : model.getRouteConfigurationDefinitions()) { 420 Resource res = config.getResource(); 421 if (res == null) { 422 res = dummy; 423 } 424 RouteConfigurationsDefinition routes 425 = groups.computeIfAbsent(res, resource -> new RouteConfigurationsDefinition()); 426 routes.getRouteConfigurations().add(config); 427 } 428 StringBuilder sbLog = new StringBuilder(); 429 for (Map.Entry<Resource, RouteConfigurationsDefinition> entry : groups.entrySet()) { 430 RouteConfigurationsDefinition def = entry.getValue(); 431 Resource resource = entry.getKey(); 432 433 StringBuilder sbLocal = new StringBuilder(); 434 doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "routeConfiguration", 435 "route-configurations", 436 sbLocal, sbLog); 437 // dump each resource into its own file 438 doDumpToDirectory(resource, sbLocal, "route-configurations", "xml", files); 439 } 440 if (!sbLog.isEmpty() && log) { 441 LOG.info("Dumping {} route-configurations as XML", size); 442 LOG.info("{}", sbLog); 443 } 444 } 445 } 446 447 if (include.contains("*") || include.contains("all") || include.contains("rests")) { 448 int size = model.getRestDefinitions().size(); 449 if (size > 0) { 450 Map<Resource, RestsDefinition> groups = new LinkedHashMap<>(); 451 for (RestDefinition rest : model.getRestDefinitions()) { 452 Resource res = rest.getResource(); 453 if (res == null) { 454 res = dummy; 455 } 456 RestsDefinition routes = groups.computeIfAbsent(res, resource -> new RestsDefinition()); 457 routes.getRests().add(rest); 458 } 459 StringBuilder sbLog = new StringBuilder(); 460 for (Map.Entry<Resource, RestsDefinition> entry : groups.entrySet()) { 461 RestsDefinition def = entry.getValue(); 462 Resource resource = entry.getKey(); 463 464 StringBuilder sbLocal = new StringBuilder(); 465 doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "rest", "rests", sbLocal, sbLog); 466 // dump each resource into its own file 467 doDumpToDirectory(resource, sbLocal, "rests", "xml", files); 468 } 469 if (!sbLog.isEmpty() && log) { 470 LOG.info("Dumping {} rests as XML", size); 471 LOG.info("{}", sbLog); 472 } 473 } 474 } 475 476 if (include.contains("*") || include.contains("all") || include.contains("routeTemplates") 477 || include.contains("route-templates")) { 478 int size = model.getRouteTemplateDefinitions().size(); 479 if (size > 0) { 480 Map<Resource, RouteTemplatesDefinition> groups = new LinkedHashMap<>(); 481 for (RouteTemplateDefinition rt : model.getRouteTemplateDefinitions()) { 482 Resource res = rt.getResource(); 483 if (res == null) { 484 res = dummy; 485 } 486 RouteTemplatesDefinition routes = groups.computeIfAbsent(res, resource -> new RouteTemplatesDefinition()); 487 routes.getRouteTemplates().add(rt); 488 } 489 StringBuilder sbLog = new StringBuilder(); 490 for (Map.Entry<Resource, RouteTemplatesDefinition> entry : groups.entrySet()) { 491 RouteTemplatesDefinition def = entry.getValue(); 492 Resource resource = entry.getKey(); 493 494 StringBuilder sbLocal = new StringBuilder(); 495 doDumpXml(camelContext, def, resource == dummy ? null : resource, dumper, "routeTemplate", 496 "route-templates", sbLocal, sbLog); 497 // dump each resource into its own file 498 doDumpToDirectory(resource, sbLocal, "route-templates", "xml", files); 499 } 500 if (!sbLog.isEmpty() && log) { 501 LOG.info("Dumping {} route-templates as XML", size); 502 LOG.info("{}", sbLog); 503 } 504 } 505 } 506 507 if (output != null && !files.isEmpty()) { 508 // all XML files need to have <camel> as root tag 509 doAdjustXmlFiles(files); 510 } 511 } 512 513 protected void doDumpXmlBeans( 514 CamelContext camelContext, List beans, Resource resource, 515 ModelToXMLDumper dumper, String kind, StringBuilder sbLocal, StringBuilder sbLog) { 516 try { 517 String dump = dumper.dumpBeansAsXml(camelContext, beans); 518 sbLocal.append(dump); 519 appendLogDump(resource, dump, sbLog); 520 } catch (Exception e) { 521 LOG.warn("Error dumping {}} to XML due to {}. This exception is ignored.", kind, e.getMessage(), e); 522 } 523 } 524 525 protected void doDumpXml( 526 CamelContext camelContext, NamedNode def, Resource resource, 527 ModelToXMLDumper dumper, String replace, String kind, StringBuilder sbLocal, StringBuilder sbLog) { 528 try { 529 String xml = dumper.dumpModelAsXml(camelContext, def, resolvePlaceholders, generatedIds); 530 // remove spring schema xmlns that camel-jaxb dumper includes 531 xml = StringHelper.replaceFirst(xml, " xmlns=\"http://camel.apache.org/schema/spring\">", ">"); 532 xml = xml.replace("</" + replace + ">", "</" + replace + ">\n"); 533 // remove outer tag (routes, rests, etc) 534 replace = replace + "s"; 535 xml = StringHelper.replaceFirst(xml, "<" + replace + ">", ""); 536 xml = StringHelper.replaceFirst(xml, "</" + replace + ">", ""); 537 538 sbLocal.append(xml); 539 appendLogDump(resource, xml, sbLog); 540 } catch (Exception e) { 541 LOG.warn("Error dumping {}} to XML due to {}. This exception is ignored.", kind, e.getMessage(), e); 542 } 543 } 544 545 protected void doDumpToDirectory(Resource resource, StringBuilder sbLocal, String kind, String ext, Set<String> files) { 546 if (output != null && !sbLocal.isEmpty()) { 547 // make sure directory exists 548 File dir = new File(output); 549 dir.mkdirs(); 550 551 String name = resolveFileName(ext, resource); 552 boolean newFile = files.isEmpty() || !files.contains(name); 553 File target = new File(output, name); 554 try { 555 if (newFile) { 556 // write as new file (override old file if exists) 557 IOHelper.writeText(sbLocal.toString(), target); 558 } else { 559 // append to existing file 560 IOHelper.appendText(sbLocal.toString(), target); 561 } 562 files.add(name); 563 LOG.info("Dumped {} to file: {}", kind, target); 564 } catch (IOException e) { 565 throw new RuntimeException("Error dumping " + kind + " to file: " + target, e); 566 } 567 } 568 } 569 570 protected void doAdjustXmlFiles(Set<String> files) { 571 for (String name : files) { 572 if (name.endsWith(".xml")) { 573 try { 574 File file = new File(output, name); 575 // wrap xml files with <camel> root tag 576 StringBuilder sb = new StringBuilder(); 577 sb.append("<camel>\n\n"); 578 String xml = IOHelper.loadText(new FileInputStream(file)); 579 sb.append(xml); 580 sb.append("\n</camel>\n"); 581 IOHelper.writeText(sb.toString(), file); 582 } catch (Exception e) { 583 LOG.warn("Error adjusting dumped XML file: {} due to {}. This exception is ignored.", name, e.getMessage(), 584 e); 585 } 586 } 587 } 588 } 589 590 protected void appendLogDump(Resource resource, String dump, StringBuilder sbLog) { 591 String loc = null; 592 if (resource != null) { 593 loc = extractLocationName(resource.getLocation()); 594 } 595 if (loc != null) { 596 sbLog.append(String.format("%nSource: %s%n%s%n%s%n", loc, DIVIDER, dump)); 597 } else { 598 sbLog.append(String.format("%n%n%s%n", dump)); 599 } 600 } 601 602 private static final class DummyResource extends ResourceSupport { 603 604 private DummyResource(String scheme, String location) { 605 super(scheme, location); 606 } 607 608 @Override 609 public boolean exists() { 610 return true; 611 } 612 613 @Override 614 public InputStream getInputStream() throws IOException { 615 return null; // not in use 616 } 617 } 618 619 private static String extractLocationName(String loc) { 620 if (loc == null) { 621 return null; 622 } 623 loc = stripSourceLocationLineNumber(loc); 624 if (loc != null) { 625 if (loc.contains(":")) { 626 // strip prefix 627 loc = StringHelper.after(loc, ":", loc); 628 629 // file based such as xml and yaml 630 loc = FileUtil.stripPath(loc); 631 } 632 } 633 return loc; 634 } 635 636 protected String resolveFileName(String ext, Resource resource) { 637 if (outputFileName != null) { 638 return outputFileName; 639 } 640 641 // compute name from resource or auto-generated 642 String name = resource != null ? resource.getLocation() : null; 643 if (name == null) { 644 name = "dump" + counter.incrementAndGet(); 645 } 646 // strip scheme 647 if (name.contains(":")) { 648 name = StringHelper.after(name, ":"); 649 } 650 return FileUtil.onlyName(name) + "." + ext; 651 } 652 653}