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