All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jdesktop.beansbinding.AutoBinding Maven / Gradle / Ivy

The newest version!
/***********************************************************************************************************************
 *
 * BetterBeansBinding - keeping JavaBeans in sync
 * ==============================================
 *
 * Copyright (C) 2009 by Tidalwave s.a.s. (http://www.tidalwave.it)
 * http://betterbeansbinding.kenai.com
 *
 * This is derived work from BeansBinding: http://beansbinding.dev.java.net
 * BeansBinding is copyrighted (C) by Sun Microsystems, Inc.
 *
 ***********************************************************************************************************************
 *
 * This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General
 * Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 ***********************************************************************************************************************
 *
 * $Id: AutoBinding.java 75 2009-06-12 19:53:46Z fabriziogiudici $
 *
 **********************************************************************************************************************/
package org.jdesktop.beansbinding;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import org.jdesktop.beansbinding.util.Parameters;

/**
 * An implementation of {@code Binding} that automatically syncs the source
 * and target by refreshing and saving according to one of three update
 * strategies. The update strategy is specified for an {@code AutoBinding}
 * on creation, and is one of:
 * 

*

    *
  • {@code AutoBinding.UpdateStrategy.READ_ONCE}
  • *
  • {@code AutoBinding.UpdateStrategy.READ}
  • *
  • {@code AutoBinding.UpdateStrategy.READ_WRITE}
  • *
*

* The behavior of {@code AutoBinding} for each * of the update strategies is defined as follows: *

*

* * * * * * * * * * * * * * * * * *
{@code READ_ONCE}    * Summary:
* Tries to sync the target from the source only once, at bind time. *

* Details:
* At bind time, tries to sync the target from the source, by calling * {@code refreshAndNotify}. No further automatic syncing is done. *


{@code READ}    * Summary:
* Tries to keep the target in sync with the source. *

* Details:
* At bind time, tries to sync the target from the source, by calling * {@code refreshAndNotify}. Then automatically tries to sync the target * from the source by calling {@code refreshAndNotify} when either the source * changes value, or the target changes from unwriteable to writeable. *


{@code READ_WRITE}    * Summary:
* Tries to keep both the source and target in sync with each other. *

* Details:
* At bind time, first tries to sync the target from the source, by calling * {@code refresh}. If the call succeeds, notifies the binding listeners * of a successful sync. If the call returns failure, then tries to instead sync the * source from the target by calling {@code save}. If this second call succeeds, * notifies the binding listeners of a succesful sync. If it returns failure, notifies * the binding listeners of a failed sync, indicating the reason for the original * refresh failure. *

* Automatically responds to changes in the state of the source as follows: * If the change represents a value change, use the try-refresh-then-save * procedure mentioned above. Otherwise, if the change represents the * source becoming writeable, tries to update the source from the target * by calling {@code saveAndNotify}. *

* Automatically responds to changes in the state of the target as follows: * If the change represents the target simply becoming writeable, try to * sync the target from the source by calling {@code refreshAndNotify}. If * the change represents the target becoming writeable and the value changing * together, use the try-refresh-then-save procedure mentioned above. Finally * if the change represents the target's value changing alone, first try to * sync the source from the target by calling {@code save}. * If that succeeds, notify the listeners of a successful sync. If it * returns failure due to conversion or validation, notify the listeners of a sync * failure, providing the conversion or validation failure. If it fails for * any other reason, then instead try to sync the target from the source by * calling {@code refresh}. If this succeeds, notify the listeners of successful * sync. Otherwise notify them of failure with the reasons for the original * save failure. *

* * @param the type of source object * @param the type of value that the source property represents * @param the type of target object * @param the type of value that the target property represents * * @author Shannon Hickey * @author Fabrizio Giudici */ public class AutoBinding extends Binding { private UpdateStrategy strategy; /** * Create an instance of {@code AutoBinding} between two properties of two objects, * with the given update strategy. * * @param strategy the update strategy * @param sourceObject the source object * @param sourceProperty a property on the source object * @param targetObject the target object * @param targetProperty a property on the target object * @param name a name for the {@code Binding} * @throws IllegalArgumentException if the source property or target property is {@code null} */ protected AutoBinding (final @Nonnull UpdateStrategy strategy, final @Nonnull SS sourceObject, final @Nonnull Property sourceProperty, final @Nonnull TS targetObject, final @Nonnull Property targetProperty, final @CheckForNull String name) { super(sourceObject, sourceProperty, targetObject, targetProperty, name); Parameters.checkNotNull(strategy, "strategy"); this.strategy = strategy; } /** * Returns the {@code AutoBinding's} update strategy. * * @return the update strategy */ public final UpdateStrategy getUpdateStrategy() { return strategy; } private final void tryRefreshThenSave() { SyncFailure refreshFailure = refresh(); if (refreshFailure == null) { notifySynced(); } else { SyncFailure saveFailure = save(); if (saveFailure == null) { notifySynced(); } else { notifySyncFailed(refreshFailure); } } } private final void trySaveThenRefresh() { SyncFailure saveFailure = save(); if (saveFailure == null) { notifySynced(); } else if ((saveFailure.getType() == SyncFailureType.CONVERSION_FAILED) || (saveFailure.getType() == SyncFailureType.VALIDATION_FAILED)) { notifySyncFailed(saveFailure); } else { SyncFailure refreshFailure = refresh(); if (refreshFailure == null) { notifySynced(); } else { notifySyncFailed(saveFailure); } } } protected void bindImpl() { UpdateStrategy strat = getUpdateStrategy(); if (strat == UpdateStrategy.READ_ONCE) { refreshAndNotify(); } else if (strat == UpdateStrategy.READ) { refreshAndNotify(); } else { tryRefreshThenSave(); } } protected void unbindImpl() { } /** * Returns a string representing the internal state of the {@code Binding}. * This method is intended to be used for debugging purposes only, * and the content and format of the returned string may vary between * implementations. The returned string may be empty but may not * be {@code null}. * * @return a string representing the state of the {@code Binding}. */ protected String paramString() { return super.paramString() + ", updateStrategy=" + getUpdateStrategy(); } protected void sourceChangedImpl(PropertyStateEvent pse) { if (strategy == UpdateStrategy.READ_ONCE) { // nothing to do } else if (strategy == UpdateStrategy.READ) { if (pse.getValueChanged()) { refreshAndNotify(); } } else if (strategy == UpdateStrategy.READ_WRITE) { if (pse.getValueChanged()) { tryRefreshThenSave(); } else if (pse.isWriteable()) { saveAndNotify(); } } } protected void targetChangedImpl(PropertyStateEvent pse) { if (strategy == UpdateStrategy.READ_ONCE) { // nothing to do } else if (strategy == UpdateStrategy.READ) { if (pse.getWriteableChanged() && pse.isWriteable()) { refreshAndNotify(); } } else if (strategy == UpdateStrategy.READ_WRITE) { if (pse.getWriteableChanged() && pse.isWriteable()) { if (pse.getValueChanged()) { tryRefreshThenSave(); } else { refreshAndNotify(); } } else if (pse.getValueChanged()) { trySaveThenRefresh(); } } } /** * An enumeration representing the possible update strategies of an * {@code AutoBinding}. See {@code AutoBinding's} class level * documentation for complete * details on the sync behavior for each possible update strategy. */ public enum UpdateStrategy { /** * An update strategy where the {@code AutoBinding} tries to sync the * target from the source only once, at bind time. */ READ_ONCE, /** * An update strategy where the {@code AutoBinding} tries to keep the target * in sync with the source. */ READ, /** * An update strategy where the {@code AutoBinding} tries to keep both the * source and target in sync with each other. */ READ_WRITE; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy