001package org.apache.archiva.redback.common.config.acc2; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.redback.common.config.api.ConfigRegistry; 023import org.apache.archiva.redback.common.config.api.RegistryException; 024import org.apache.archiva.redback.common.config.api.RegistryListener; 025import org.apache.commons.configuration2.*; 026import org.apache.commons.configuration2.builder.ConfigurationBuilder; 027import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; 028import org.apache.commons.configuration2.builder.combined.CombinedConfigurationBuilder; 029import org.apache.commons.configuration2.builder.fluent.Parameters; 030import org.apache.commons.configuration2.convert.DefaultListDelimiterHandler; 031import org.apache.commons.configuration2.event.ConfigurationEvent; 032import org.apache.commons.configuration2.event.EventSource; 033import org.apache.commons.configuration2.ex.ConfigurationException; 034import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; 035import org.apache.commons.configuration2.interpol.ConfigurationInterpolator; 036import org.apache.commons.configuration2.interpol.DefaultLookups; 037import org.apache.commons.configuration2.interpol.InterpolatorSpecification; 038import org.apache.commons.configuration2.io.ClasspathLocationStrategy; 039import org.apache.commons.configuration2.io.FileHandler; 040import org.apache.commons.configuration2.io.FileLocatorUtils; 041import org.apache.commons.configuration2.io.FileSystem; 042import org.apache.commons.configuration2.tree.DefaultExpressionEngine; 043import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols; 044import org.apache.commons.configuration2.tree.NodeCombiner; 045import org.apache.commons.configuration2.tree.UnionCombiner; 046import org.apache.commons.lang3.StringUtils; 047import org.slf4j.Logger; 048import org.slf4j.LoggerFactory; 049import org.springframework.stereotype.Service; 050 051import javax.annotation.PostConstruct; 052import java.io.*; 053import java.net.MalformedURLException; 054import java.net.URL; 055import java.nio.file.Path; 056import java.util.*; 057import java.util.regex.Matcher; 058import java.util.regex.Pattern; 059import java.util.stream.Collectors; 060import java.util.stream.StreamSupport; 061 062/** 063 * Implementation of the registry component using 064 * <a href="https://commons.apache.org/proper/commons-configuration/index.html">Commons Configuration 2</a>. 065 * The use of Commons Configuration enables a variety of sources to be used, including XML files, properties, JNDI, JDBC, etc. 066 * <p/> 067 * The component can be configured using the {@link #combinedConfigurationDefinition} configuration item, the content of which should take 068 * the format of an input to the Commons Configuration 069 * <a href="http://commons.apache.org/commons/configuration/howto_configurationbuilder.html">configuration 070 * builder</a>. 071 */ 072@Service( "acc2-configuration" ) 073public class CommonsConfigurationRegistry 074 implements ConfigRegistry 075{ 076 private static final Pattern DOT_NAME_PATTERN = Pattern.compile( "([^.]+)(\\..*)*" ); 077 078 /** 079 * The combined configuration instance that houses the registry. 080 */ 081 private Configuration configuration; 082 083 084 private ConfigurationBuilder<? extends Configuration> configurationBuilder; 085 private boolean combined = true; 086 private final Map<String, ConfigurationBuilder<? extends Configuration>> builderMap = new HashMap<>( ); 087 088 private final Logger logger = LoggerFactory.getLogger( getClass( ) ); 089 090 private String propertyDelimiter = "."; 091 092 private boolean addSystemProperties = false; 093 094 final CfgListener listener = new CfgListener( this ); 095 096 /** 097 * The configuration properties for the registry. This should take the format of an input to the Commons 098 * Configuration 099 * <a href="https://commons.apache.org/proper/commons-configuration/userguide/howto_combinedbuilder.html#The_configuration_definition_file">configuration 100 * builder</a>. 101 */ 102 private String combinedConfigurationDefinition; 103 104 105 public CommonsConfigurationRegistry( ) 106 { 107 // Default constructor 108 } 109 110 111 public CommonsConfigurationRegistry( CombinedConfiguration configuration, CombinedConfigurationBuilder configurationBuilder ) 112 { 113 if ( configuration == null ) 114 { 115 throw new NullPointerException( "configuration can not be null" ); 116 } 117 if ( configurationBuilder == null ) 118 { 119 throw new NullPointerException( "configuration builder cannot be null for a combined configuration" ); 120 } 121 this.combined = true; 122 setConfiguration(configuration); 123 this.configurationBuilder = configurationBuilder; 124 } 125 126 @SuppressWarnings( "WeakerAccess" ) 127 public CommonsConfigurationRegistry( Configuration configuration, ConfigurationBuilder<? extends Configuration> configurationBuilder ) 128 { 129 if ( configuration == null ) 130 { 131 throw new NullPointerException( "configuration can not be null" ); 132 } 133 setConfiguration(configuration); 134 this.configurationBuilder = configurationBuilder; 135 if (configuration instanceof CombinedConfiguration) { 136 this.combined = true; 137 } 138 } 139 140 public void setConfiguration( Configuration configuration ) 141 { 142 this.configuration = configuration; 143 if (configuration instanceof EventSource ) { 144 EventSource evs = (EventSource) configuration; 145 evs.removeEventListener( ConfigurationEvent.ANY, listener ); 146 evs.addEventListener( ConfigurationEvent.ANY, listener ); 147 evs.addEventListener( ConfigurationEvent.SUBNODE_CHANGED, listener ); 148 } 149 } 150 151 @Override 152 public String dump( ) 153 { 154 StringBuilder buffer = new StringBuilder( "Configuration Dump:\n"); 155 Iterable<String> it = () -> configuration.getKeys(); 156 return buffer.append(StreamSupport.stream( it.spliterator(), false ).map( k -> 157 "\""+k+"\" = \""+configuration.getProperty( k ).toString() + "\"").collect(Collectors.joining( "\n" ) )).toString(); 158 } 159 160 @Override 161 public boolean isEmpty( ) 162 { 163 return configuration.isEmpty( ); 164 } 165 166 @Override 167 public ConfigRegistry getSubset( String key ) throws RegistryException 168 { 169 if (configuration instanceof BaseHierarchicalConfiguration) { 170 BaseHierarchicalConfiguration cfg = (BaseHierarchicalConfiguration) configuration; 171 if (cfg.containsKey( key )) 172 { 173 try 174 { 175 return new CommonsConfigurationRegistry( cfg.configurationAt( key, true ), null ); 176 } catch ( ConfigurationRuntimeException ex ) { 177 logger.error("There are multiple entries for the given key"); 178 throw new RegistryException( "Subset for multiple key entries is not possible."); 179 } 180 } else { 181 return new CommonsConfigurationRegistry( cfg.subset( key ), null ); 182 } 183 } 184 return new CommonsConfigurationRegistry( configuration.subset( key ), configurationBuilder ); 185 } 186 187 @Override 188 public List<String> getList( String key ) 189 { 190 List<String> result = configuration.getList( String.class, key ); 191 return result == null ? new ArrayList<>( ) : result; 192 } 193 194 @Override 195 public List<ConfigRegistry> getSubsetList( String key ) throws RegistryException 196 { 197 198 if (configuration instanceof BaseHierarchicalConfiguration) { 199 BaseHierarchicalConfiguration cfg = (BaseHierarchicalConfiguration)configuration; 200 return cfg.configurationsAt( key, true ).stream().map(c -> new CommonsConfigurationRegistry( c, null )).collect( Collectors.toList() ); 201 } else 202 { 203 List<ConfigRegistry> subsets = new ArrayList<>( ); 204 boolean done = false; 205 do 206 { 207 ConfigRegistry registry = null; 208 try 209 { 210 registry = getSubset( key + "(" + subsets.size( ) + ")" ); 211 } 212 catch ( RegistryException e ) 213 { 214 throw new RegistryException( "Could not retrieve subset from key "+key+": "+e.getMessage() ); 215 } 216 if ( !registry.isEmpty( ) ) 217 { 218 subsets.add( registry ); 219 } 220 else 221 { 222 done = true; 223 } 224 } 225 while ( !done ); 226 return subsets; 227 } 228 } 229 230 @Override 231 public ConfigRegistry getPartOfCombined( String name ) 232 { 233 if ( combined ) 234 { 235 CombinedConfiguration config = (CombinedConfiguration) configuration; 236 Configuration newCfg = config.getConfiguration( name ); 237 ConfigurationBuilder<? extends Configuration> cfgBuilder = null; 238 try 239 { 240 if ( builderMap.containsKey( name ) ) 241 { 242 cfgBuilder = builderMap.get( name ); 243 } 244 else 245 { 246 cfgBuilder = configurationBuilder == null ? null : 247 ( (CombinedConfigurationBuilder) configurationBuilder ).getNamedBuilder( name ); 248 builderMap.put( name, cfgBuilder ); 249 } 250 } 251 catch ( ConfigurationException e ) 252 { 253 logger.error( "Could not retrieve configuration builder: " + e.getMessage( ) ); 254 } 255 return newCfg == null ? null : new CommonsConfigurationRegistry( newCfg, cfgBuilder ); 256 } 257 return null; 258 } 259 260 @Override 261 public Map<String, String> getProperties( String key ) 262 { 263 Configuration configuration = this.configuration.subset( key ); 264 265 Map<String, String> properties = new TreeMap<>( ); 266 Iterator<String> cfgIter = configuration.getKeys( ); 267 String property; 268 while ( cfgIter.hasNext( ) ) 269 { 270 property = cfgIter.next( ); 271 List<String> l = configuration.getList( String.class, property ); 272 String value = String.join( ",", l ); 273 properties.put( property, value ); 274 } 275 return properties; 276 } 277 278 @Override 279 public void save( ) 280 throws RegistryException 281 { 282 if ( configuration instanceof FileBasedConfiguration ) 283 { 284 FileBasedConfiguration fileConfiguration = (FileBasedConfiguration) configuration; 285 FileHandler fileHandler; 286 if ( configurationBuilder != null && configurationBuilder instanceof FileBasedConfigurationBuilder ) 287 { 288 FileBasedConfigurationBuilder cfgBuilder = (FileBasedConfigurationBuilder) configurationBuilder; 289 fileHandler = cfgBuilder.getFileHandler( ); 290 } 291 else 292 { 293 fileHandler = new FileHandler( fileConfiguration ); 294 } 295 try 296 { 297 fileHandler.save( ); 298 } 299 catch ( ConfigurationException e ) 300 { 301 throw new RegistryException( e.getMessage( ), e ); 302 } 303 } 304 else 305 { 306 throw new RegistryException( "Can only save file-based configurations" ); 307 } 308 } 309 310 @Override 311 public void registerChangeListener( RegistryListener listener, String prefix) 312 { 313 this.listener.registerChangeListener(listener, prefix); 314 } 315 316 @Override 317 public boolean unregisterChangeListener( RegistryListener listener ) 318 { 319 return this.listener.unregisterChangeListener(listener); 320 } 321 322 @Override 323 public Collection<String> getBaseKeys( ) 324 { 325 Iterable<String> iterable = ( ) -> configuration.getKeys( ); 326 return StreamSupport.stream( iterable.spliterator( ), true ) 327 .map( DOT_NAME_PATTERN::matcher ) 328 .filter( Matcher::matches ) 329 .map( k -> k.group( 1 ) ).collect( Collectors.toSet( ) ); 330 331 } 332 333 @Override 334 public Collection<String> getKeys( ) 335 { 336 Iterable<String> iterable = ( ) -> configuration.getKeys( ); 337 return StreamSupport.stream( iterable.spliterator( ), true ).collect( Collectors.toSet( ) ); 338 } 339 340 @Override 341 public Collection<String> getKeys( String prefix ) 342 { 343 Iterable<String> iterable = ( ) -> configuration.getKeys( prefix ); 344 return StreamSupport.stream( iterable.spliterator( ), true ).collect( Collectors.toSet( ) ); 345 } 346 347 @Override 348 public void remove( String key ) 349 { 350 configuration.clearProperty( key ); 351 } 352 353 @Override 354 public void removeSubset( String key ) 355 { 356 getKeys( key ).forEach( k -> configuration.clearProperty( k ) ); 357 } 358 359 @Override 360 public Object getValue( String key ) { 361 return configuration.getProperty( key ); 362 } 363 364 @Override 365 public String getString( String key ) 366 { 367 return configuration.getString( key ); 368 } 369 370 @Override 371 public String getString( String key, String defaultValue ) 372 { 373 return configuration.getString( key, defaultValue ); 374 } 375 376 @Override 377 public void setString( String key, String value ) 378 { 379 configuration.setProperty( key, value ); 380 } 381 382 @Override 383 public int getInt( String key ) 384 { 385 return configuration.getInt( key ); 386 } 387 388 @Override 389 public int getInt( String key, int defaultValue ) 390 { 391 return configuration.getInt( key, defaultValue ); 392 } 393 394 @Override 395 public void setInt( String key, int value ) 396 { 397 configuration.setProperty( key, value ); 398 } 399 400 @Override 401 public boolean getBoolean( String key ) 402 { 403 return configuration.getBoolean( key ); 404 } 405 406 @Override 407 public boolean getBoolean( String key, boolean defaultValue ) 408 { 409 return configuration.getBoolean( key, defaultValue ); 410 } 411 412 @Override 413 public void setBoolean( String key, boolean value ) 414 { 415 configuration.setProperty( key, value ); 416 } 417 418 @Override 419 public void addConfigurationFromResource( String name, String resource ) 420 throws RegistryException 421 { 422 addConfigurationFromResource( name, resource, null ); 423 } 424 425 @Override 426 public void addConfigurationFromResource( String name, String resource, String prefix ) 427 throws RegistryException 428 { 429 if ( configuration instanceof CombinedConfiguration ) 430 { 431 String atPrefix = StringUtils.isEmpty( prefix ) ? null : prefix; 432 CombinedConfiguration configuration = (CombinedConfiguration) this.configuration; 433 if ( resource.endsWith( ".properties" ) ) 434 { 435 try 436 { 437 logger.debug( "Loading properties configuration from classloader resource: {}", resource ); 438 FileBasedConfigurationBuilder<PropertiesConfiguration> builder = new FileBasedConfigurationBuilder<>( PropertiesConfiguration.class ) 439 .configure( new Parameters( ).properties( ) 440 .setLocationStrategy( new ClasspathLocationStrategy( ) ) 441 .setFileName( resource ) ); 442 builderMap.put( name, builder ); 443 configuration.addConfiguration( builder.getConfiguration( ), name, atPrefix ); 444 } 445 catch ( ConfigurationException e ) 446 { 447 throw new RegistryException( 448 "Unable to add configuration from resource '" + resource + "': " + e.getMessage( ), e ); 449 } 450 } 451 else if ( resource.endsWith( ".xml" ) ) 452 { 453 try 454 { 455 logger.debug( "Loading XML configuration from classloader resource: {}", resource ); 456 FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class ) 457 .configure( new Parameters( ).xml( ) 458 .setLocationStrategy( new ClasspathLocationStrategy( ) ) 459 .setFileName( resource ) ); 460 builderMap.put( name, builder ); 461 configuration.addConfiguration( builder.getConfiguration( ), name, atPrefix ); 462 } 463 catch ( ConfigurationException e ) 464 { 465 throw new RegistryException( 466 "Unable to add configuration from resource '" + resource + "': " + e.getMessage( ), e ); 467 } 468 } 469 else 470 { 471 throw new RegistryException( 472 "Unable to add configuration from resource '" + resource + "': unrecognised type" ); 473 } 474 } 475 else 476 { 477 throw new RegistryException( "The underlying configuration object is not a combined configuration " ); 478 } 479 } 480 481 @Override 482 public void addConfigurationFromFile( String name, Path file ) throws RegistryException 483 { 484 addConfigurationFromFile( name, file, "" ); 485 } 486 487 @Override 488 public void addConfigurationFromFile( String name, Path file, String prefix ) 489 throws RegistryException 490 { 491 if ( this.configuration instanceof CombinedConfiguration ) 492 { 493 String atPrefix = StringUtils.isEmpty( prefix ) ? null : prefix; 494 CombinedConfiguration configuration = (CombinedConfiguration) this.configuration; 495 String fileName = file.getFileName( ).toString( ); 496 if ( fileName.endsWith( ".properties" ) ) 497 { 498 try 499 { 500 logger.debug( "Loading properties configuration from file: {}", file ); 501 FileBasedConfigurationBuilder<PropertiesConfiguration> builder = new FileBasedConfigurationBuilder<>( PropertiesConfiguration.class ) 502 .configure( new Parameters( ).properties( ) 503 .setFileSystem( FileLocatorUtils.DEFAULT_FILE_SYSTEM ) 504 .setLocationStrategy( FileLocatorUtils.DEFAULT_LOCATION_STRATEGY ) 505 .setFile( file.toFile( ) ) ); 506 // builder is needed for save 507 builderMap.put( name, builder ); 508 configuration.addConfiguration( builder.getConfiguration( ), name, atPrefix ); 509 } 510 catch ( ConfigurationException e ) 511 { 512 throw new RegistryException( 513 "Unable to add configuration from file '" + file.getFileName( ) + "': " + e.getMessage( ), e ); 514 } 515 } 516 else if ( fileName.endsWith( ".xml" ) ) 517 { 518 try 519 { 520 logger.debug( "Loading XML configuration from file: {}", file ); 521 FileBasedConfigurationBuilder<XMLConfiguration> builder = new FileBasedConfigurationBuilder<>( XMLConfiguration.class ) 522 .configure( new Parameters( ).xml( ) 523 .setFileSystem( FileLocatorUtils.DEFAULT_FILE_SYSTEM ) 524 .setLocationStrategy( FileLocatorUtils.DEFAULT_LOCATION_STRATEGY ) 525 .setFile( file.toFile( ) ) ); 526 builderMap.put( name, builder ); 527 configuration.addConfiguration( builder.getConfiguration( ), name, atPrefix ); 528 } 529 catch ( ConfigurationException e ) 530 { 531 throw new RegistryException( 532 "Unable to add configuration from file '" + file.getFileName( ) + "': " + e.getMessage( ), e ); 533 } 534 } 535 else 536 { 537 throw new RegistryException( 538 "Unable to add configuration from file '" + file.getFileName( ) + "': unrecognised type" ); 539 } 540 } 541 else 542 { 543 throw new RegistryException( "The underlying configuration is not a combined configuration object." ); 544 } 545 } 546 547 /** 548 * This is a dummy FileSystem needed to load the CombinedConfiguration declaration from a String. 549 */ 550 class StringFileSystem extends FileSystem 551 { 552 553 final String content; 554 String encoding = "UTF-8"; 555 556 StringFileSystem( String content ) 557 { 558 this.content = content; 559 } 560 561 562 @SuppressWarnings( "unused" ) 563 StringFileSystem( String encoding, String content ) 564 { 565 this.encoding = encoding; 566 this.content = content; 567 } 568 569 @Override 570 public InputStream getInputStream( URL url ) throws ConfigurationException 571 { 572 try 573 { 574 return new ByteArrayInputStream( content.getBytes( encoding ) ); 575 } 576 catch ( UnsupportedEncodingException e ) 577 { 578 logger.error( "Bad encoding for FileSystem" ); 579 throw new ConfigurationException( "Bad encoding specified" ); 580 } 581 } 582 583 @Override 584 public OutputStream getOutputStream( URL url ) 585 { 586 return new ByteArrayOutputStream( 0 ); 587 } 588 589 @Override 590 public OutputStream getOutputStream( File file ) 591 { 592 return new ByteArrayOutputStream( 0 ); 593 } 594 595 @Override 596 public String getPath( File file, URL url, String basePath, String fileName ) 597 { 598 return basePath + "/" + fileName; 599 } 600 601 @Override 602 public String getBasePath( String path ) 603 { 604 return path; 605 } 606 607 @Override 608 public String getFileName( String path ) 609 { 610 return path; 611 } 612 613 @Override 614 public URL locateFromURL( String basePath, String fileName ) 615 { 616 try 617 { 618 return new URL( "file://" + getPath( null, null, basePath, fileName ) ); 619 } 620 catch ( MalformedURLException e ) 621 { 622 // ignore 623 return null; 624 } 625 } 626 627 @Override 628 public URL getURL( String basePath, String fileName ) throws MalformedURLException 629 { 630 return new URL( "file://" + getPath( null, null, basePath, fileName ) ); 631 } 632 633 } 634 635 @Override 636 @PostConstruct 637 public void initialize( ) 638 throws RegistryException 639 { 640 try 641 { 642 CombinedConfiguration configuration; 643 if ( StringUtils.isNotBlank( combinedConfigurationDefinition ) ) 644 { 645 String interpolatedProps; 646 Parameters params = new Parameters( ); 647 DefaultExpressionEngineSymbols symbols = new DefaultExpressionEngineSymbols.Builder( DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS ) 648 .setPropertyDelimiter( propertyDelimiter ) 649 .setIndexStart( "(" ) 650 .setIndexEnd( ")" ) 651 .setEscapedDelimiter( "\\" + propertyDelimiter ) 652 .create( ); 653 DefaultExpressionEngine expressionEngine = new DefaultExpressionEngine( symbols ); 654 655 // It allows to use system properties in the XML declaration. 656 657 ConfigurationInterpolator interpolator = ConfigurationInterpolator.fromSpecification( new InterpolatorSpecification.Builder( ).withDefaultLookup( DefaultLookups.SYSTEM_PROPERTIES.getLookup( ) ).create( ) ); 658 interpolatedProps = interpolator.interpolate( combinedConfigurationDefinition ).toString( ); 659 logger.debug( "Loading configuration into commons-configuration, xml {}", interpolatedProps ); 660 // This is the builder configuration for the XML declaration, that contains the definition 661 // for the sources that are used for the CombinedConfiguration. 662 FileSystem fs = new StringFileSystem( interpolatedProps ); 663 FileBasedConfigurationBuilder<XMLConfiguration> cfgBuilder = 664 new FileBasedConfigurationBuilder<>( 665 XMLConfiguration.class ) 666 .configure( params.xml( ) 667 .setFileSystem( fs ) 668 .setFileName( "config.xml" ) 669 .setListDelimiterHandler( 670 new DefaultListDelimiterHandler( ',' ) ) 671 .setExpressionEngine( expressionEngine ) 672 .setThrowExceptionOnMissing( false ) ); 673 674 CombinedConfigurationBuilder builder = new CombinedConfigurationBuilder( ). 675 configure( params.combined( ).setDefinitionBuilder( cfgBuilder ) ); 676 // The builder is needed later for saving of the file parts in the combined configuration. 677 this.configurationBuilder = builder; 678 configuration = builder.getConfiguration( ); 679 680 681 } 682 else 683 { 684 logger.debug( "Creating a default configuration - no configuration was provided" ); 685 NodeCombiner combiner = new UnionCombiner( ); 686 configuration = new CombinedConfiguration( combiner ); 687 this.configurationBuilder = null; 688 } 689 690 // In the end, we add the system properties to the combined configuration 691 if ( addSystemProperties ) 692 { 693 configuration.addConfiguration( new SystemConfiguration( ), "SystemProperties" ); 694 } 695 696 this.configuration = configuration; 697 } 698 catch ( ConfigurationException e ) 699 { 700 logger.error( "Fatal error, while reading the configuration definition: " + e.getMessage( ) ); 701 logger.error( "The definition was:" ); 702 logger.error( combinedConfigurationDefinition ); 703 throw new RegistryException( e.getMessage( ), e ); 704 } 705 } 706 707 public void setCombinedConfigurationDefinition( String combinedConfigurationDefinition ) 708 { 709 this.combinedConfigurationDefinition = combinedConfigurationDefinition; 710 } 711 712 public String getPropertyDelimiter( ) 713 { 714 return propertyDelimiter; 715 } 716 717 public void setPropertyDelimiter( String propertyDelimiter ) 718 { 719 this.propertyDelimiter = propertyDelimiter; 720 } 721 722 723 public ConfigurationBuilder<? extends Configuration> getConfigurationBuilder( ) 724 { 725 return configurationBuilder; 726 } 727 728 /** 729 * Returns true, if the system properties are added to the base configuration. Otherwise system properties 730 * can still be interpolated by ${sys:var} syntax. 731 * 732 * @return True, if system properties are added to the configuration root 733 */ 734 public boolean isAddSystemProperties( ) 735 { 736 return addSystemProperties; 737 } 738 739 /** 740 * Set to true, if the system properties should be added to the base configuration. 741 * If set to false, system properties are no direct part of the configuration. 742 * 743 * @param addSystemProperties True, or false. 744 */ 745 public void setAddSystemProperties( boolean addSystemProperties ) 746 { 747 this.addSystemProperties = addSystemProperties; 748 } 749}