Spec-Zone .ru
спецификации, руководства, описания, API
001/*
002 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package javafx.beans.property.adapter;
027
028import com.sun.javafx.binding.ExpressionHelper;
029import com.sun.javafx.property.adapter.PropertyDescriptor;
030import javafx.beans.InvalidationListener;
031import javafx.beans.property.BooleanProperty;
032import javafx.beans.value.ChangeListener;
033import javafx.beans.value.ObservableValue;
034
035import java.lang.reflect.InvocationTargetException;
036import java.lang.reflect.UndeclaredThrowableException;
037import sun.misc.Cleaner;
038
039import java.security.AccessControlContext;
040import java.security.AccessController;
041import java.security.PrivilegedAction;
042
043import sun.reflect.misc.MethodUtil;
044
045/**
046 * A {@code JavaBeanBooleanProperty} provides an adapter between a regular
047 * Java Bean property of type {@code boolean} or {@code Boolean} and a JavaFX 
048 * {@code BooleanProperty}. It cannot be created directly, but a 
049 * {@link JavaBeanBooleanPropertyBuilder} has to be used.
050 * <p>
051 * As a minimum, the Java Bean must implement a getter and a setter for the
052 * property. If the getter of an instance of this class is called, the property of 
053 * the Java Bean is returned. If the setter is called, the value will be passed
054 * to the Java Bean property. If the Java Bean property is bound (i.e. it supports
055 * PropertyChangeListeners), this {@code JavaBeanBooleanProperty} will be 
056 * aware of changes in the Java Bean. Otherwise it can be notified about
057 * changes by calling {@link #fireValueChangedEvent()}. If the Java Bean property 
058 * is also constrained (i.e. it supports VetoableChangeListeners), this 
059 * {@code JavaBeanBooleanProperty} will reject changes, if it is bound to an 
060 * {@link javafx.beans.value.ObservableValue ObservableValue&lt;Boolean&gt;}.
061 * 
062 * @see javafx.beans.property.BooleanProperty
063 * @see JavaBeanBooleanPropertyBuilder
064 */
065public final class JavaBeanBooleanProperty extends BooleanProperty implements JavaBeanProperty<Boolean> {
066
067    private final PropertyDescriptor descriptor;
068    private final PropertyDescriptor.Listener<Boolean> listener;
069
070    private ObservableValue<? extends Boolean> observable = null;
071    private ExpressionHelper<Boolean> helper = null;
072
073    private final AccessControlContext acc = AccessController.getContext();
074
075    JavaBeanBooleanProperty(PropertyDescriptor descriptor, Object bean) {
076        this.descriptor = descriptor;
077        this.listener = descriptor.new Listener<Boolean>(bean, this);
078        descriptor.addListener(listener);
079        Cleaner.create(this, new Runnable() {
080            @Override
081            public void run() {
082                JavaBeanBooleanProperty.this.descriptor.removeListener(listener);
083            }
084        });
085    }
086
087    /**
088     * {@inheritDoc}
089     * 
090     * @throws UndeclaredThrowableException if calling the getter of the Java Bean
091     * property throws an {@code IllegalAccessException} or an 
092     * {@code InvocationTargetException}.
093     */
094    @Override
095    public boolean get() {
096        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
097            public Boolean run() {
098                try {
099                    return (Boolean)MethodUtil.invoke(descriptor.getGetter(), getBean(), (Object[])null);
100                } catch (IllegalAccessException e) {
101                    throw new UndeclaredThrowableException(e);
102                } catch (InvocationTargetException e) {
103                    throw new UndeclaredThrowableException(e);
104                }
105            }
106        }, acc);
107    }
108
109    /**
110     * {@inheritDoc}
111     * 
112     * @throws UndeclaredThrowableException if calling the getter of the Java Bean
113     * property throws an {@code IllegalAccessException} or an 
114     * {@code InvocationTargetException}.
115     */
116    @Override
117    public void set(final boolean value) {
118        if (isBound()) {
119            throw new RuntimeException("A bound value cannot be set.");
120        }
121
122        AccessController.doPrivileged(new PrivilegedAction<Void>() {
123            public Void run() {
124                try {
125                    MethodUtil.invoke(descriptor.getSetter(), getBean(), new Object[] {value});
126                    ExpressionHelper.fireValueChangedEvent(helper);
127                } catch (IllegalAccessException e) {
128                    throw new UndeclaredThrowableException(e);
129                } catch (InvocationTargetException e) {
130                    throw new UndeclaredThrowableException(e);
131                }
132                return null;
133            }
134        }, acc);
135    }
136
137    /**
138     * {@inheritDoc}
139     */
140    @Override
141    public void bind(ObservableValue<? extends Boolean> observable) {
142        if (observable == null) {
143            throw new NullPointerException("Cannot bind to null");
144        }
145
146        if (!observable.equals(this.observable)) {
147            unbind();
148            set(observable.getValue());
149            this.observable = observable;
150            this.observable.addListener(listener);
151        }
152    }
153
154    /**
155     * {@inheritDoc}
156     */
157    @Override
158    public void unbind() {
159        if (observable != null) {
160            observable.removeListener(listener);
161            observable = null;
162        }
163    }
164
165    /**
166     * {@inheritDoc}
167     */
168    @Override
169    public boolean isBound() {
170        return observable != null;
171    }
172
173    /**
174     * {@inheritDoc}
175     */
176    @Override
177    public Object getBean() {
178        return listener.getBean();
179    }
180
181    /**
182     * {@inheritDoc}
183     */
184    @Override
185    public String getName() {
186        return descriptor.getName();
187    }
188
189    /**
190     * {@inheritDoc}
191     */
192    @Override
193    public void addListener(ChangeListener<? super Boolean> listener) {
194        helper = ExpressionHelper.addListener(helper, this, listener);
195    }
196
197    /**
198     * {@inheritDoc}
199     */
200    @Override
201    public void removeListener(ChangeListener<? super Boolean> listener) {
202        helper = ExpressionHelper.removeListener(helper, listener);
203    }
204
205    /**
206     * {@inheritDoc}
207     */
208    @Override
209    public void addListener(InvalidationListener listener) {
210        helper = ExpressionHelper.addListener(helper, this, listener);
211    }
212
213    /**
214     * {@inheritDoc}
215     */
216    @Override
217    public void removeListener(InvalidationListener listener) {
218        helper = ExpressionHelper.removeListener(helper, listener);
219    }
220
221    /**
222     * {@inheritDoc}
223     */
224    @Override
225    public void fireValueChangedEvent() {
226        ExpressionHelper.fireValueChangedEvent(helper);
227    }
228
229    /**
230     * {@inheritDoc}
231     */
232    @Override
233    public void dispose() {
234        descriptor.removeListener(listener);
235
236    }
237
238    /**
239     * Returns a string representation of this {@code JavaBeanBooleanProperty} object.
240     * @return a string representation of this {@code JavaBeanBooleanProperty} object.
241     */
242    @Override
243    public String toString() {
244        final Object bean = getBean();
245        final String name = getName();
246        final StringBuilder result = new StringBuilder("BooleanProperty [");
247        if (bean != null) {
248            result.append("bean: ").append(bean).append(", ");
249        }
250        if ((name != null) && (!name.equals(""))) {
251            result.append("name: ").append(name).append(", ");
252        }
253        if (isBound()) {
254            result.append("bound, ");
255        }
256        result.append("value: ").append(get());
257        result.append("]");
258        return result.toString();
259    }
260}