⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 binding.java

📁 java属性邦定的(JSR-295)的一个实现
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * Copyright (C) 2007 Sun Microsystems, Inc. All rights reserved. Use is
 * subject to license terms.
 */

package org.jdesktop.beansbinding;

import java.util.List;
import java.util.ArrayList;
import java.beans.*;

/**
 * {@code Binding} is an abstract class that represents the concept of a
 * binding between two properties, typically of two objects, and contains
 * methods for explicitly syncing the values of the two properties. {@code Binding}
 * itself does no automatic syncing between property values. Subclasses
 * will typically keep the values in sync according to some strategy.
 * <p>
 * Some {@code Bindings} are managed, often by another {@code Binding}.
 * A managed {@code Binding} does not allow certain methods to be called by
 * the user. These methods are identified in their documentation.
 * Subclasses should call {@code setManaged(true)} to make themselves managed.
 * {@code Binding} provides protected versions of the managed methods with the
 * suffix {@code "Unmanaged"} for subclasses to use internally without
 * checking whether or not they are managed.
 * <p>
 * Any {@code PropertyResolutionExceptions} thrown by {@code Property}
 * objects used by this binding are allowed to flow through to the caller
 * of the {@code Binding} methods.
 *
 * @param <SS> the type of source object
 * @param <SV> the type of value that the source property represents
 * @param <TS> the type of target object
 * @param <TV> the type of value that the target property represents
 *
 * @author Shannon Hickey
 */
public abstract class Binding<SS, SV, TS, TV> {

    private String name;
    private SS sourceObject;
    private TS targetObject;
    private Property<SS, SV> sourceProperty;
    private Property<TS, TV> targetProperty;
    private Validator<? super SV> validator;
    private Converter<SV, TV> converter;
    private TV sourceNullValue;
    private SV targetNullValue;
    private TV sourceUnreadableValue;
    private boolean sourceUnreadableValueSet;
    private List<BindingListener> listeners;
    private PropertyStateListener psl;
    private boolean ignoreChange;
    private boolean isManaged;
    private boolean isBound;
    private PropertyChangeSupport changeSupport;

    /**
     * An enumeration representing the reasons a sync ({@code save} or {@code refresh})
     * can fail on a {@code Binding}.
     *
     * @see Binding#refresh
     * @see Binding#save
     */
    public enum SyncFailureType {
        
        /**
         * A {@code refresh} failed because the {@code Binding's} target property is unwriteable
         * for the {@code Binding's} target object.
         */
        TARGET_UNWRITEABLE,
        
        /**
         * A {@code save} failed because the {@code Binding's} source property is unwriteable
         * for the {@code Binding's} source object.
         */
        SOURCE_UNWRITEABLE,
        
        /**
         * A {@code save} failed because the {@code Binding's} target property is unreadable
         * for the {@code Binding's} target object.
         */
        TARGET_UNREADABLE,

        /**
         * A {@code refresh} failed because the {@code Binding's} source property is unreadable
         * for the {@code Binding's} source object.
         */
        SOURCE_UNREADABLE,
        
        /**
         * A {@code save} failed due to a conversion failure on the value
         * returned by the {@code Binding's} target property for the {@code Binding's}
         * target object.
         */
        CONVERSION_FAILED,
        
        /**
         * A {@code save} failed due to a validation failure on the value
         * returned by the {@code Binding's} target property for the {@code Binding's}
         * target object.
         */
        VALIDATION_FAILED
    }

    /**
     * {@code SyncFailure} represents a failure to sync ({@code save} or {@code refresh}) a
     * {@code Binding}.
     */
    public static final class SyncFailure {
        private SyncFailureType type;
        private Object reason;

        private static SyncFailure TARGET_UNWRITEABLE = new SyncFailure(SyncFailureType.TARGET_UNWRITEABLE);
        private static SyncFailure SOURCE_UNWRITEABLE = new SyncFailure(SyncFailureType.SOURCE_UNWRITEABLE);
        private static SyncFailure TARGET_UNREADABLE = new SyncFailure(SyncFailureType.TARGET_UNREADABLE);
        private static SyncFailure SOURCE_UNREADABLE = new SyncFailure(SyncFailureType.SOURCE_UNREADABLE);

        private static SyncFailure conversionFailure(RuntimeException rte) {
            return new SyncFailure(rte);
        }

        private static SyncFailure validationFailure(Validator.Result result) {
            return new SyncFailure(result);
        }

        private SyncFailure(SyncFailureType type) {
            if (type == SyncFailureType.CONVERSION_FAILED || type == SyncFailureType.VALIDATION_FAILED) {
                throw new IllegalArgumentException();
            }

            this.type = type;
        }

        private SyncFailure(RuntimeException exception) {
            this.type = SyncFailureType.CONVERSION_FAILED;
            this.reason = exception;
        }

        private SyncFailure(Validator.Result result) {
            this.type = SyncFailureType.VALIDATION_FAILED;
            this.reason = result;
        }

        /**
         * Returns the type of failure.
         *
         * @return the type of failure
         */
        public SyncFailureType getType() {
            return type;
        }

        /**
         * Returns the exception that occurred during conversion if
         * this failure represents a conversion failure. Throws
         * {@code UnsupportedOperationException} otherwise.
         *
         * @return the exception that occurred during conversion
         * @throws UnsupportedOperationException if the type of failure
         *         is not {@code SyncFailureType.CONVERSION_FAILED}
         */
        public RuntimeException getConversionException() {
            if (type != SyncFailureType.CONVERSION_FAILED) {
                throw new UnsupportedOperationException();
            }
            
            return (RuntimeException)reason;
        }

        /**
         * Returns the result that was returned from the
         * {@code Binding's} validator if this failure represents a
         * validation failure. Throws {@code UnsupportedOperationException} otherwise.
         *
         * @return the result that was returned from the {@code Binding's} validator
         * @throws UnsupportedOperationException if the type of failure
         *         is not {@code SyncFailureType.VALIDATION_FAILED}
         */
        public Validator.Result getValidationResult() {
            if (type != SyncFailureType.VALIDATION_FAILED) {
                throw new UnsupportedOperationException();
            }
            
            return (Validator.Result)reason;
        }

        /**
         * Returns a string representation of the {@code SyncFailure}. 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 representation of this {@code SyncFailure}
         */
        public String toString() {
            return type + (reason == null ? "" : ": " + reason.toString());
        }
    }

    /**
     * Encapsulates the result from calling
     * {@link org.jdesktop.beansbinding.Binding#getSourceValueForTarget} or
     * {@link org.jdesktop.beansbinding.Binding#getTargetValueForSource}, which
     * can either be a successful value or a failure.
     */
    public static final class ValueResult<V> {
        private V value;
        private SyncFailure failure;

        private ValueResult(V value) {
            this.value = value;
        }

        private ValueResult(SyncFailure failure) {
            if (failure == null) {
                throw new AssertionError();
            }

            this.failure = failure;
        }

        /**
         * Returns {@code true} if this {@code ValueResult} represents
         * a failure and {@code false} otherwise.
         *
         * @return {@code true} if this {@code ValueResult} represents
         *         a failure and {@code false} otherwise
         * @see #getFailure
         */
        public boolean failed() {
            return failure != null;
        }

        /**
         * Returns the resulting value if this {@code ValueResult} does
         * not represent a failure and throws {@code UnsupportedOperationException}
         * otherwise.
         *
         * @return the resulting value
         * @throws UnsupportedOperationException if this {@code ValueResult} represents a failure
         * @see #failed
         */
        public V getValue() {
            if (failed()) {
                throw new UnsupportedOperationException();
            }

            return value;
        }

        /**
         * Returns the failure if this {@code ValueResult} represents
         * a failure and throws {@code UnsupportedOperationException}
         * otherwise.
         *
         * @return the failure
         * @throws UnsupportedOperationException if this {@code ValueResult} does not represent a failure
         * @see #failed
         */
        public SyncFailure getFailure() {
            if (!failed()) {
                throw new UnsupportedOperationException();
            }
            
            return failure;
        }

        /**
         * Returns a string representation of the {@code ValueResult}. 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 representation of this {@code ValueResult}
         */
        public String toString() {
            return value == null ? "failure: " + failure : "value: " + value;
        }
    }

    /**
     * Create an instance of {@code Binding} between two properties of two objects.
     *
     * @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 Binding(SS sourceObject, Property<SS, SV> sourceProperty, TS targetObject, Property<TS, TV> targetProperty, String name) {
        setSourceProperty(sourceProperty);
        setTargetProperty(targetProperty);

        this.sourceObject = sourceObject;
        this.sourceProperty = sourceProperty;
        this.targetObject = targetObject;
        this.targetProperty = targetProperty;
        this.name = name;
    }

    /**
     * Sets the {@code Binding's} source property.
     * <p>
     * {@code Binding} fires a property change notification with
     * property name {@code "sourceProperty"} when the value of
     * this property changes.
     * <p>
     * This method may not be called on a bound binding.
     *
     * @param sourceProperty the source property
     * @throws IllegalArgumentException if the source property is {@code null}
     * @throws IllegalStateException if the {@code Binding} is bound
     * @see #isBound()
     */
    protected final void setSourceProperty(Property<SS, SV> sourceProperty) {
        throwIfBound();
        if (sourceProperty == null) {
            throw new IllegalArgumentException("source property can't be null");
        }
        Property<SS, SV> old = this.sourceProperty;
        this.sourceProperty = sourceProperty;
        firePropertyChange("sourceProperty", old, sourceProperty);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -