001    /*
002     * Copyright 2002-2007 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.support;
017    
018    import org.springframework.beans.BeanWrapper;
019    import org.springframework.beans.BeanWrapperImpl;
020    import org.springframework.beans.BeansException;
021    import org.springframework.beans.PropertyAccessor;
022    import org.springframework.binding.MutablePropertyAccessStrategy;
023    import org.springframework.binding.value.ValueModel;
024    import org.springframework.binding.value.support.ValueHolder;
025    
026    /**
027     * An implementation of <code>MutablePropertyAccessStrategy</code> that provides access 
028     * to the properties of a JavaBean.
029     * 
030     * <p>As this class delegates to a <code>BeanWrapper</code> for property access, there is 
031     * full support for <b>nested properties</b>, enabling the setting/getting
032     * of properties on subproperties to an unlimited depth.
033     *   
034     * @author Oliver Hutchison
035     * @author Arne Limburg
036     * @see org.springframework.beans.BeanWrapper
037     */
038    public class BeanPropertyAccessStrategy extends AbstractPropertyAccessStrategy {
039    
040        private final BeanWrapper beanWrapper;
041    
042        /**
043         * Creates a new instance of BeanPropertyAccessStrategy that will provide access
044         * to the properties of the provided JavaBean.
045         * 
046         * @param bean JavaBean to be accessed through this class. 
047         */
048        public BeanPropertyAccessStrategy(Object bean) {
049            this(new ValueHolder(bean));
050        }
051    
052        /**
053         * Creates a new instance of BeanPropertyAccessStrategy that will provide access
054         * to the JavaBean contained by the provided value model.  
055         * 
056         * @param domainObjectHolder value model that holds the JavaBean to 
057         * be accessed through this class
058         */
059        public BeanPropertyAccessStrategy(final ValueModel domainObjectHolder) {
060            super(domainObjectHolder);
061            this.beanWrapper = new BeanWrapperImpl(false);
062            this.beanWrapper.setWrappedInstance(domainObjectHolder.getValue());
063        }
064    
065        /**
066         * Creates a child instance of BeanPropertyAccessStrategy that will delegate to its 
067         * parent for property access.
068         * 
069         * @param parent BeanPropertyAccessStrategy which will be used to provide property access
070         * @param basePropertyPath property path that will as a base when accessing the parent   
071         * BeanPropertyAccessStrategy
072         */
073        protected BeanPropertyAccessStrategy(BeanPropertyAccessStrategy parent, String basePropertyPath) {
074            super(parent, basePropertyPath);
075            this.beanWrapper = parent.beanWrapper;
076        }
077    
078        /**
079         * Provides <code>BeanWrapper</code> access to subclasses. 
080         * @return Spring <code>BeanWrapper</code> used to access the bean.
081         */
082        protected BeanWrapper getBeanWrapper() {
083            return beanWrapper;
084        }
085        
086        /**
087         * Provides <code>BeanWrapper</code> access to subclasses. 
088         * @return Spring <code>BeanWrapper</code> used to access the bean.
089         */
090        protected PropertyAccessor getPropertyAccessor() {
091            return beanWrapper;
092        }
093      
094        public MutablePropertyAccessStrategy getPropertyAccessStrategyForPath(String propertyPath) throws BeansException {
095            return new BeanPropertyAccessStrategy(this, getFullPropertyPath(propertyPath));
096        }
097    
098        public MutablePropertyAccessStrategy newPropertyAccessStrategy(ValueModel domainObjectHolder) {
099            return new BeanPropertyAccessStrategy(domainObjectHolder);
100        }
101        
102        protected void domainObjectChanged() {
103            beanWrapper.setWrappedInstance(getDomainObject());
104        }
105    }