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.commons.configuration2.builder; 018 019import java.util.Collection; 020import java.util.Collections; 021import java.util.HashMap; 022import java.util.Iterator; 023import java.util.Map; 024 025import org.apache.commons.configuration2.ConfigurationUtils; 026import org.apache.commons.configuration2.ImmutableConfiguration; 027import org.apache.commons.configuration2.Initializable; 028import org.apache.commons.configuration2.beanutils.BeanDeclaration; 029import org.apache.commons.configuration2.beanutils.BeanHelper; 030import org.apache.commons.configuration2.beanutils.ConstructorArg; 031import org.apache.commons.configuration2.event.Event; 032import org.apache.commons.configuration2.event.EventListener; 033import org.apache.commons.configuration2.event.EventListenerList; 034import org.apache.commons.configuration2.event.EventListenerRegistrationData; 035import org.apache.commons.configuration2.event.EventSource; 036import org.apache.commons.configuration2.event.EventType; 037import org.apache.commons.configuration2.ex.ConfigurationException; 038import org.apache.commons.configuration2.ex.ConfigurationRuntimeException; 039import org.apache.commons.configuration2.reloading.ReloadingController; 040 041/** 042 * <p> 043 * An implementation of the {@code ConfigurationBuilder} interface which is able 044 * to create different concrete {@code ImmutableConfiguration} implementations based on 045 * reflection. 046 * </p> 047 * <p> 048 * When constructing an instance of this class the concrete 049 * {@code ImmutableConfiguration} implementation class has to be provided. Then 050 * properties for the new {@code ImmutableConfiguration} instance can be set. The first 051 * call to {@code getConfiguration()} creates and initializes the new 052 * {@code ImmutableConfiguration} object. It is cached and returned by subsequent calls. 053 * This cache - and also the initialization properties set so far - can be 054 * flushed by calling one of the {@code reset()} methods. That way other 055 * {@code ImmutableConfiguration} instances with different properties can be created. 056 * </p> 057 * <p> 058 * If the newly created {@code ImmutableConfiguration} object implements the 059 * {@code Initializable} interface, its {@code initialize()} method is called 060 * after all initialization properties have been set. This way a concrete 061 * implementation class can perform arbitrary initialization steps. 062 * </p> 063 * <p> 064 * There are multiple options for setting up a {@code BasicConfigurationBuilder} 065 * instance: 066 * </p> 067 * <ul> 068 * <li>All initialization properties can be set in one or multiple calls of the 069 * {@code configure()} method. In each call an arbitrary number of 070 * {@link BuilderParameters} objects can be passed. The API allows method 071 * chaining and is intended to be used from Java code.</li> 072 * <li>If builder instances are created by other means - e.g. using a dependency 073 * injection framework -, the fluent API approach may not be suitable. For those 074 * use cases it is also possible to pass in all initialization parameters as a 075 * map. The keys of the map have to match initialization properties of the 076 * {@code ImmutableConfiguration} object to be created, the values are the corresponding 077 * property values. For instance, the key <em>throwExceptionOnMissing</em> in 078 * the map will cause the method {@code setThrowExceptionOnMissing()} on the 079 * {@code ImmutableConfiguration} object to be called with the corresponding value as 080 * parameter.</li> 081 * </ul> 082 * <p> 083 * A builder instance can be constructed with an <em>allowFailOnInit</em> 084 * flag. If set to <strong>true</strong>, exceptions during initialization 085 * of the configuration are ignored; in such a case an empty configuration 086 * object is returned. A use case for this flag is a scenario in which a 087 * configuration is optional and created on demand the first time configuration 088 * data is to be stored. Consider an application that stores user-specific 089 * configuration data in the user's home directory: When started for the first 090 * time by a new user there is no configuration file; so it makes sense to 091 * start with an empty configuration object. On application exit, settings 092 * can be stored in this object and written to the associated file. Then they 093 * are available on next application start. 094 * </p> 095 * <p> 096 * This class is thread-safe. Multiple threads can modify initialization 097 * properties and call {@code getConfiguration()}. However, the intended use 098 * case is that the builder is configured by a single thread first. Then 099 * {@code getConfiguration()} can be called concurrently, and it is guaranteed 100 * that always the same {@code ImmutableConfiguration} instance is returned until the 101 * builder is reset. 102 * </p> 103 * 104 * @version $Id: BasicConfigurationBuilder.java 1842194 2018-09-27 22:24:23Z ggregory $ 105 * @since 2.0 106 * @param <T> the concrete type of {@code ImmutableConfiguration} objects created by this 107 * builder 108 */ 109public class BasicConfigurationBuilder<T extends ImmutableConfiguration> implements 110 ConfigurationBuilder<T> 111{ 112 /** The class of the objects produced by this builder instance. */ 113 private final Class<? extends T> resultClass; 114 115 /** An object managing the event listeners registered at this builder. */ 116 private final EventListenerList eventListeners; 117 118 /** A flag whether exceptions on initializing configurations are allowed. */ 119 private final boolean allowFailOnInit; 120 121 /** The map with current initialization parameters. */ 122 private Map<String, Object> parameters; 123 124 /** The current bean declaration. */ 125 private BeanDeclaration resultDeclaration; 126 127 /** The result object of this builder. */ 128 private volatile T result; 129 130 /** 131 * Creates a new instance of {@code BasicConfigurationBuilder} and 132 * initializes it with the given result class. No initialization properties 133 * are set. 134 * 135 * @param resCls the result class (must not be <b>null</b>) 136 * @throws IllegalArgumentException if the result class is <b>null</b> 137 */ 138 public BasicConfigurationBuilder(final Class<? extends T> resCls) 139 { 140 this(resCls, null); 141 } 142 143 /** 144 * Creates a new instance of {@code BasicConfigurationBuilder} and 145 * initializes it with the given result class and an initial set of builder 146 * parameters. The <em>allowFailOnInit</em> flag is set to 147 * <strong>false</strong>. 148 * 149 * @param resCls the result class (must not be <b>null</b>) 150 * @param params a map with initialization parameters 151 * @throws IllegalArgumentException if the result class is <b>null</b> 152 */ 153 public BasicConfigurationBuilder(final Class<? extends T> resCls, final Map<String, Object> params) 154 { 155 this(resCls, params, false); 156 } 157 158 /** 159 * Creates a new instance of {@code BasicConfigurationBuilder} and 160 * initializes it with the given result class, an initial set of builder 161 * parameters, and the <em>allowFailOnInit</em> flag. The map with 162 * parameters may be <b>null</b>, in this case no initialization parameters 163 * are set. 164 * 165 * @param resCls the result class (must not be <b>null</b>) 166 * @param params a map with initialization parameters 167 * @param allowFailOnInit a flag whether exceptions on initializing a newly 168 * created {@code ImmutableConfiguration} object are allowed 169 * @throws IllegalArgumentException if the result class is <b>null</b> 170 */ 171 public BasicConfigurationBuilder(final Class<? extends T> resCls, 172 final Map<String, Object> params, final boolean allowFailOnInit) 173 { 174 if (resCls == null) 175 { 176 throw new IllegalArgumentException("Result class must not be null!"); 177 } 178 179 resultClass = resCls; 180 this.allowFailOnInit = allowFailOnInit; 181 eventListeners = new EventListenerList(); 182 updateParameters(params); 183 } 184 185 /** 186 * Returns the result class of this builder. The objects produced by this 187 * builder have the class returned here. 188 * 189 * @return the result class of this builder 190 */ 191 public Class<? extends T> getResultClass() 192 { 193 return resultClass; 194 } 195 196 /** 197 * Returns the <em>allowFailOnInit</em> flag. See the header comment for 198 * information about this flag. 199 * 200 * @return the <em>allowFailOnInit</em> flag 201 */ 202 public boolean isAllowFailOnInit() 203 { 204 return allowFailOnInit; 205 } 206 207 /** 208 * Sets the initialization parameters of this builder. Already existing 209 * parameters are replaced by the content of the given map. 210 * 211 * @param params the new initialization parameters of this builder; can be 212 * <b>null</b>, then all initialization parameters are removed 213 * @return a reference to this builder for method chaining 214 */ 215 public synchronized BasicConfigurationBuilder<T> setParameters( 216 final Map<String, Object> params) 217 { 218 updateParameters(params); 219 return this; 220 } 221 222 /** 223 * Adds the content of the given map to the already existing initialization 224 * parameters. 225 * 226 * @param params the map with additional initialization parameters; may be 227 * <b>null</b>, then this call has no effect 228 * @return a reference to this builder for method chaining 229 */ 230 public synchronized BasicConfigurationBuilder<T> addParameters( 231 final Map<String, Object> params) 232 { 233 final Map<String, Object> newParams = 234 new HashMap<>(getParameters()); 235 if (params != null) 236 { 237 newParams.putAll(params); 238 } 239 updateParameters(newParams); 240 return this; 241 } 242 243 /** 244 * Appends the content of the specified {@code BuilderParameters} objects to 245 * the current initialization parameters. Calling this method multiple times 246 * will create a union of the parameters provided. 247 * 248 * @param params an arbitrary number of objects with builder parameters 249 * @return a reference to this builder for method chaining 250 * @throws NullPointerException if a <b>null</b> array is passed 251 */ 252 public BasicConfigurationBuilder<T> configure(final BuilderParameters... params) 253 { 254 final Map<String, Object> newParams = new HashMap<>(); 255 for (final BuilderParameters p : params) 256 { 257 newParams.putAll(p.getParameters()); 258 handleEventListenerProviders(p); 259 } 260 261 return setParameters(newParams); 262 } 263 264 /** 265 * {@inheritDoc} This implementation creates the result configuration on 266 * first access. Later invocations return the same object until this builder 267 * is reset. The double-check idiom for lazy initialization is used (Bloch, 268 * Effective Java, item 71). 269 */ 270 @Override 271 public T getConfiguration() throws ConfigurationException 272 { 273 fireBuilderEvent(new ConfigurationBuilderEvent(this, 274 ConfigurationBuilderEvent.CONFIGURATION_REQUEST)); 275 276 T resObj = result; 277 boolean created = false; 278 if (resObj == null) 279 { 280 synchronized (this) 281 { 282 resObj = result; 283 if (resObj == null) 284 { 285 result = resObj = createResult(); 286 created = true; 287 } 288 } 289 } 290 291 if (created) 292 { 293 fireBuilderEvent(new ConfigurationBuilderResultCreatedEvent(this, 294 ConfigurationBuilderResultCreatedEvent.RESULT_CREATED, 295 resObj)); 296 } 297 return resObj; 298 } 299 300 /** 301 * {@inheritDoc} This implementation also takes care that the event listener 302 * is added to the managed configuration object. 303 * 304 * @throws IllegalArgumentException if the event type or the listener is 305 * <b>null</b> 306 */ 307 @Override 308 public <E extends Event> void addEventListener( 309 final EventType<E> eventType, final EventListener<? super E> listener) 310 { 311 installEventListener(eventType, listener); 312 } 313 314 /** 315 * {@inheritDoc} This implementation also takes care that the event listener 316 * is removed from the managed configuration object. 317 */ 318 @Override 319 public <E extends Event> boolean removeEventListener( 320 final EventType<E> eventType, final EventListener<? super E> listener) 321 { 322 fetchEventSource().removeEventListener(eventType, listener); 323 return eventListeners.removeEventListener(eventType, listener); 324 } 325 326 /** 327 * Clears an existing result object. An invocation of this method causes a 328 * new {@code ImmutableConfiguration} object to be created the next time 329 * {@link #getConfiguration()} is called. 330 */ 331 public void resetResult() 332 { 333 T oldResult; 334 synchronized (this) 335 { 336 oldResult = result; 337 result = null; 338 resultDeclaration = null; 339 } 340 341 if (oldResult != null) 342 { 343 removeEventListeners(oldResult); 344 } 345 fireBuilderEvent(new ConfigurationBuilderEvent(this, 346 ConfigurationBuilderEvent.RESET)); 347 } 348 349 /** 350 * Removes all initialization parameters of this builder. This method can be 351 * called if this builder is to be reused for creating result objects with a 352 * different configuration. 353 */ 354 public void resetParameters() 355 { 356 setParameters(null); 357 } 358 359 /** 360 * Resets this builder. This is a convenience method which combines calls to 361 * {@link #resetResult()} and {@link #resetParameters()}. 362 */ 363 public synchronized void reset() 364 { 365 resetParameters(); 366 resetResult(); 367 } 368 369 /** 370 * Connects this builder with a {@code ReloadingController}. With this 371 * method support for reloading can be added to an arbitrary builder object. 372 * Event listeners are registered at the reloading controller and this 373 * builder with connect both objects: 374 * <ul> 375 * <li>When the reloading controller detects that a reload is required, the 376 * builder's {@link #resetResult()} method is called; so the managed result 377 * object is invalidated.</li> 378 * <li>When a new result object has been created the controller's reloading 379 * state is reset, so that new changes can be detected again.</li> 380 * </ul> 381 * 382 * @param controller the {@code ReloadingController} to connect to (must not 383 * be <b>null</b>) 384 * @throws IllegalArgumentException if the controller is <b>null</b> 385 */ 386 public final void connectToReloadingController( 387 final ReloadingController controller) 388 { 389 if (controller == null) 390 { 391 throw new IllegalArgumentException( 392 "ReloadingController must not be null!"); 393 } 394 ReloadingBuilderSupportListener.connect(this, controller); 395 } 396 397 /** 398 * Creates a new, initialized result object. This method is called by 399 * {@code getConfiguration()} if no valid result object exists. This base 400 * implementation performs two steps: 401 * <ul> 402 * <li>{@code createResultInstance()} is called to create a new, 403 * uninitialized result object.</li> 404 * <li>{@code initResultInstance()} is called to process all initialization 405 * parameters.</li> 406 * </ul> 407 * It also evaluates the <em>allowFailOnInit</em> flag, i.e. if 408 * initialization causes an exception and this flag is set, the exception is 409 * ignored, and the newly created, uninitialized configuration is returned. 410 * Note that this method is called in a synchronized block. 411 * 412 * @return the newly created result object 413 * @throws ConfigurationException if an error occurs 414 */ 415 protected T createResult() throws ConfigurationException 416 { 417 final T resObj = createResultInstance(); 418 419 try 420 { 421 initResultInstance(resObj); 422 } 423 catch (final ConfigurationException cex) 424 { 425 if (!isAllowFailOnInit()) 426 { 427 throw cex; 428 } 429 } 430 431 return resObj; 432 } 433 434 /** 435 * Creates the new, uninitialized result object. This is the first step of 436 * the process of producing a result object for this builder. This 437 * implementation uses the {@link BeanHelper} class to create a new object 438 * based on the {@link BeanDeclaration} returned by 439 * {@link #getResultDeclaration()}. Note: This method is invoked in a 440 * synchronized block. 441 * 442 * @return the newly created, yet uninitialized result object 443 * @throws ConfigurationException if an exception occurs 444 */ 445 protected T createResultInstance() throws ConfigurationException 446 { 447 final Object bean = fetchBeanHelper().createBean(getResultDeclaration()); 448 checkResultInstance(bean); 449 return getResultClass().cast(bean); 450 } 451 452 /** 453 * Initializes a newly created result object. This is the second step of the 454 * process of producing a result object for this builder. This 455 * implementation uses the {@link BeanHelper} class to initialize the 456 * object's property based on the {@link BeanDeclaration} returned by 457 * {@link #getResultDeclaration()}. Note: This method is invoked in a 458 * synchronized block. This is required because internal state is accessed. 459 * Sub classes must not call this method without proper synchronization. 460 * 461 * @param obj the object to be initialized 462 * @throws ConfigurationException if an error occurs 463 */ 464 protected void initResultInstance(final T obj) throws ConfigurationException 465 { 466 fetchBeanHelper().initBean(obj, getResultDeclaration()); 467 registerEventListeners(obj); 468 handleInitializable(obj); 469 } 470 471 /** 472 * Returns the {@code BeanDeclaration} that is used to create and initialize 473 * result objects. The declaration is created on first access (by invoking 474 * {@link #createResultDeclaration(Map)}) based on the current 475 * initialization parameters. 476 * 477 * @return the {@code BeanDeclaration} for dynamically creating a result 478 * object 479 * @throws ConfigurationException if an error occurs 480 */ 481 protected final synchronized BeanDeclaration getResultDeclaration() 482 throws ConfigurationException 483 { 484 if (resultDeclaration == null) 485 { 486 resultDeclaration = createResultDeclaration(getFilteredParameters()); 487 } 488 return resultDeclaration; 489 } 490 491 /** 492 * Returns a (unmodifiable) map with the current initialization parameters 493 * set for this builder. The map is populated with the parameters set using 494 * the various configuration options. 495 * 496 * @return a map with the current set of initialization parameters 497 */ 498 protected final synchronized Map<String, Object> getParameters() 499 { 500 if (parameters != null) 501 { 502 return parameters; 503 } 504 return Collections.emptyMap(); 505 } 506 507 /** 508 * Obtains the {@code BeanHelper} object to be used when dealing with bean 509 * declarations. This method checks whether this builder was configured with 510 * a specific {@code BeanHelper} instance. If so, this instance is used. 511 * Otherwise, the default {@code BeanHelper} is returned. 512 * 513 * @return the {@code BeanHelper} to be used 514 */ 515 protected final BeanHelper fetchBeanHelper() 516 { 517 final BeanHelper helper = 518 BasicBuilderParameters.fetchBeanHelper(getParameters()); 519 return (helper != null) ? helper : BeanHelper.INSTANCE; 520 } 521 522 /** 523 * Creates a new {@code BeanDeclaration} which is used for creating new 524 * result objects dynamically. This implementation creates a specialized 525 * {@code BeanDeclaration} object that is initialized from the given map of 526 * initialization parameters. The {@code BeanDeclaration} must be 527 * initialized with the result class of this builder, otherwise exceptions 528 * will be thrown when the result object is created. Note: This method is 529 * invoked in a synchronized block. 530 * 531 * @param params a snapshot of the current initialization parameters 532 * @return the {@code BeanDeclaration} for creating result objects 533 * @throws ConfigurationException if an error occurs 534 */ 535 protected BeanDeclaration createResultDeclaration( 536 final Map<String, Object> params) throws ConfigurationException 537 { 538 return new BeanDeclaration() 539 { 540 @Override 541 public Map<String, Object> getNestedBeanDeclarations() 542 { 543 // no nested beans 544 return Collections.emptyMap(); 545 } 546 547 @Override 548 public Collection<ConstructorArg> getConstructorArgs() 549 { 550 // no constructor arguments 551 return Collections.emptySet(); 552 } 553 554 @Override 555 public Map<String, Object> getBeanProperties() 556 { 557 // the properties are equivalent to the parameters 558 return params; 559 } 560 561 @Override 562 public Object getBeanFactoryParameter() 563 { 564 return null; 565 } 566 567 @Override 568 public String getBeanFactoryName() 569 { 570 return null; 571 } 572 573 @Override 574 public String getBeanClassName() 575 { 576 return getResultClass().getName(); 577 } 578 }; 579 } 580 581 /** 582 * Copies all {@code EventListener} objects registered at this builder to 583 * the specified target configuration builder. This method is intended to be 584 * used by derived classes which support inheritance of their properties to 585 * other builder objects. 586 * 587 * @param target the target configuration builder (must not be <b>null</b>) 588 * @throws NullPointerException if the target builder is <b>null</b> 589 */ 590 protected synchronized void copyEventListeners( 591 final BasicConfigurationBuilder<?> target) 592 { 593 copyEventListeners(target, eventListeners); 594 } 595 596 /** 597 * Copies all event listeners in the specified list to the specified target 598 * configuration builder. This method is intended to be used by derived 599 * classes which have to deal with managed configuration builders that need 600 * to be initialized with event listeners. 601 * 602 * @param target the target configuration builder (must not be <b>null</b>) 603 * @param listeners the event listeners to be copied over 604 * @throws NullPointerException if the target builder is <b>null</b> 605 */ 606 protected void copyEventListeners(final BasicConfigurationBuilder<?> target, 607 final EventListenerList listeners) 608 { 609 target.eventListeners.addAll(listeners); 610 } 611 612 /** 613 * Adds the specified event listener to this object. This method is called 614 * by {@code addEventListener()}, it does the actual listener registration. 615 * Because it is final it can be called by sub classes in the constructor if 616 * there is already the need to register an event listener. 617 * 618 * @param eventType the event type object 619 * @param listener the listener to be registered 620 * @param <E> the event type 621 */ 622 protected final <E extends Event> void installEventListener( 623 final EventType<E> eventType, final EventListener<? super E> listener) 624 { 625 fetchEventSource().addEventListener(eventType, listener); 626 eventListeners.addEventListener(eventType, listener); 627 } 628 629 /** 630 * Sends the specified builder event to all registered listeners. 631 * 632 * @param event the event to be fired 633 */ 634 protected void fireBuilderEvent(final ConfigurationBuilderEvent event) 635 { 636 eventListeners.fire(event); 637 } 638 639 /** 640 * Replaces the current map with parameters by a new one. 641 * 642 * @param newParams the map with new parameters (may be <b>null</b>) 643 */ 644 private void updateParameters(final Map<String, Object> newParams) 645 { 646 final Map<String, Object> map = new HashMap<>(); 647 if (newParams != null) 648 { 649 map.putAll(newParams); 650 } 651 parameters = Collections.unmodifiableMap(map); 652 } 653 654 /** 655 * Registers the available event listeners at the given object. This method 656 * is called for each result object created by the builder. 657 * 658 * @param obj the object to initialize 659 */ 660 private void registerEventListeners(final T obj) 661 { 662 final EventSource evSrc = ConfigurationUtils.asEventSource(obj, true); 663 for (final EventListenerRegistrationData<?> regData : eventListeners 664 .getRegistrations()) 665 { 666 registerListener(evSrc, regData); 667 } 668 } 669 670 /** 671 * Removes all available event listeners from the given result object. This 672 * method is called when the result of this builder is reset. Then the old 673 * managed configuration should no longer generate events. 674 * 675 * @param obj the affected result object 676 */ 677 private void removeEventListeners(final T obj) 678 { 679 final EventSource evSrc = ConfigurationUtils.asEventSource(obj, true); 680 for (final EventListenerRegistrationData<?> regData : eventListeners 681 .getRegistrations()) 682 { 683 removeListener(evSrc, regData); 684 } 685 } 686 687 /** 688 * Returns an {@code EventSource} for the current result object. If there is 689 * no current result or if it does not extend {@code EventSource}, a dummy 690 * event source is returned. 691 * 692 * @return the {@code EventSource} for the current result object 693 */ 694 private EventSource fetchEventSource() 695 { 696 return ConfigurationUtils.asEventSource(result, true); 697 } 698 699 /** 700 * Checks whether the specified parameters object implements the 701 * {@code EventListenerProvider} interface. If so, the event listeners it 702 * provides are added to this builder. 703 * 704 * @param params the parameters object 705 */ 706 private void handleEventListenerProviders(final BuilderParameters params) 707 { 708 if (params instanceof EventListenerProvider) 709 { 710 eventListeners.addAll(((EventListenerProvider) params) 711 .getListeners()); 712 } 713 } 714 715 /** 716 * Checks whether the class of the result configuration is compatible with 717 * this builder's result class. This is done to ensure that only objects of 718 * the expected result class are created. 719 * 720 * @param inst the result instance to be checked 721 * @throws ConfigurationRuntimeException if an invalid result class is 722 * detected 723 */ 724 private void checkResultInstance(final Object inst) 725 { 726 if (!getResultClass().isInstance(inst)) 727 { 728 throw new ConfigurationRuntimeException( 729 "Incompatible result object: " + inst); 730 } 731 } 732 733 /** 734 * Returns a map with initialization parameters where all parameters 735 * starting with the reserved prefix have been filtered out. 736 * 737 * @return the filtered parameters map 738 */ 739 private Map<String, Object> getFilteredParameters() 740 { 741 final Map<String, Object> filteredMap = 742 new HashMap<>(getParameters()); 743 for (final Iterator<String> it = filteredMap.keySet().iterator(); it 744 .hasNext();) 745 { 746 final String key = it.next(); 747 if (key.startsWith(BuilderParameters.RESERVED_PARAMETER_PREFIX)) 748 { 749 it.remove(); 750 } 751 } 752 return filteredMap; 753 } 754 755 /** 756 * Performs special initialization of the result object. This method is 757 * called after parameters have been set on a newly created result instance. 758 * If supported by the result class, the {@code initialize()} method is now 759 * called. 760 * 761 * @param obj the newly created result object 762 */ 763 private void handleInitializable(final T obj) 764 { 765 if (obj instanceof Initializable) 766 { 767 ((Initializable) obj).initialize(); 768 } 769 } 770 771 /** 772 * Registers an event listener at an event source object. 773 * 774 * @param evSrc the event source 775 * @param regData the registration data object 776 * @param <E> the type of the event listener 777 */ 778 private static <E extends Event> void registerListener(final EventSource evSrc, 779 final EventListenerRegistrationData<E> regData) 780 { 781 evSrc.addEventListener(regData.getEventType(), regData.getListener()); 782 } 783 784 /** 785 * Removes an event listener from an event source object. 786 * 787 * @param evSrc the event source 788 * @param regData the registration data object 789 * @param <E> the type of the event listener 790 */ 791 private static <E extends Event> void removeListener(final EventSource evSrc, 792 final EventListenerRegistrationData<E> regData) 793 { 794 evSrc.removeEventListener(regData.getEventType(), regData.getListener()); 795 } 796}