001    /*
002     * Copyright 2002-2008 the original author or authors.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005     * use this file except in compliance with the License. You may obtain a copy of
006     * the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012     * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013     * License for the specific language governing permissions and limitations under
014     * the License.
015     */
016    package org.springframework.binding.value.support;
017    
018    import org.springframework.rules.closure.Closure;
019    import org.springframework.core.style.StylerUtils;
020    import org.springframework.util.Assert;
021    
022    /**
023     * ValueModel adding a <code>refreshable</code> aspect. A {@link Closure} is
024     * given that may be executed using the {@link #refresh()} method or forced to
025     * be executed on every {@link #getValue()}. The given refresh Closure is used
026     * to set the value before reading it.
027     *
028     * @author Keith Donald
029     */
030    public class RefreshableValueHolder extends ValueHolder {
031            private final Closure refreshFunction;
032    
033            private boolean alwaysRefresh;
034    
035            /**
036             * Constructor supplying a refresh <code>Closure</code>. Refresh has to be triggered
037             * manually.
038             */
039            public RefreshableValueHolder(Closure refreshFunction) {
040                    this(refreshFunction, false);
041            }
042    
043            /**
044             * Constructor supplying a refresh <code>Closure</code> that allways has to be triggered
045             * when reading the value.
046             */
047            public RefreshableValueHolder(Closure refreshFunction, boolean alwaysRefresh) {
048                    this(refreshFunction, alwaysRefresh, true);
049            }
050    
051            /**
052             * Constructor supplying a refresh <code>Closure</code> that allways has to be triggered
053             * when reading the value. Additionally a refresh is triggered on construction.
054             */
055            public RefreshableValueHolder(Closure refreshFunction, boolean alwaysRefresh, boolean lazyInit) {
056                    super();
057                    Assert.notNull(refreshFunction, "The refresh callback cannot be null");
058                    this.refreshFunction = refreshFunction;
059                    this.alwaysRefresh = alwaysRefresh;
060                    if (!lazyInit) {
061                            refresh();
062                    }
063            }
064    
065            /**
066             * {@inheritDoc}
067             *
068             * If allwaysRefresh is set, this method will trigger refresh() each time it is executed.
069             */
070            public Object getValue() {
071                    if (alwaysRefresh) {
072                            refresh();
073                    }
074                    return super.getValue();
075            }
076    
077            /**
078             * Refresh te value by executing the refresh <code>Closure</code>.
079             */
080            public void refresh() {
081                    if (logger.isDebugEnabled()) {
082                            logger.debug("Refreshing held value '" + StylerUtils.style(super.getValue()) + "'");
083                    }
084                    setValue(refreshFunction.call(null));
085            }
086    }