001    /*
002     * Copyright 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.BeansException;
019    import org.springframework.beans.PropertyAccessor;
020    import org.springframework.binding.MutablePropertyAccessStrategy;
021    import org.springframework.binding.value.ValueModel;
022    import org.springframework.binding.value.support.ValueHolder;
023    import org.springframework.richclient.beans.DefaultMemberPropertyAccessor;
024    
025    /**
026     * An implementation of <code>MutablePropertyAccessStrategy</code> that provides access
027     * to the properties of any object.
028     *
029     * <p>As this class delegates to a <code>DefaultMemberPropertyAccessor</code> for property access,
030     * there is full support for <b>nested properties</b> and collection types.
031     *
032     * @author Arne Limburg
033     * @see org.springframework.richclient.beans.DefaultMemberPropertyAccessor
034     */
035    public class ObjectPropertyAccessStrategy extends AbstractPropertyAccessStrategy {
036    
037        private final DefaultMemberPropertyAccessor propertyAccessor;
038    
039        /**
040         * Creates a new instance of <tt>ObjectPropertyAccessStrategy</tt>
041         * that will provide access to the properties of the provided object.
042         *
043         * @param target object to be accessed through this class.
044         */
045        public ObjectPropertyAccessStrategy(Object target) {
046            this(new ValueHolder(target));
047        }
048    
049        /**
050         * Creates a new instance of <tt>ObjectPropertyAccessStrategy</tt>
051         * that will provide access to the object contained by the provided value model.
052         *
053         * @param domainObjectHolder value model that holds the object
054         *                           to be accessed through this class
055         */
056        public ObjectPropertyAccessStrategy(final ValueModel domainObjectHolder) {
057           this(domainObjectHolder, false);
058        }
059    
060        /**
061         * Creates a new instance of <tt>ObjectPropertyAccessStrategy</tt>
062         * that will provide access to the object contained by the provided value model.
063         *
064         * @param domainObjectHolder value model that holds the object
065         *                           to be accessed through this class
066         * @param fieldAccessEnabled whether the fields of the objects
067         *                           should be accessed directly where possible
068         *                           instead of using methods
069         */
070        public ObjectPropertyAccessStrategy(final ValueModel domainObjectHolder, boolean fieldAccessEnabled) {
071           this(domainObjectHolder, fieldAccessEnabled, true);
072        }
073    
074        /**
075         * Creates a new instance of <tt>ObjectPropertyAccessStrategy</tt>
076         * that will provide access to the object contained by the provided value model.
077         *
078         * @param domainObjectHolder value model that holds the object
079         *                           to be accessed through this class
080         * @param fieldAccessEnabled whether the fields of the objects
081         *                           should be accessed directly where possible
082         *                           instead of using methods
083         * @param strictNullValueHandling whether a <tt>NullValueInNestedPathException</tt>
084         *                           should be thrown on nested null-values or <tt>null</tt> should be returned
085         */
086        public ObjectPropertyAccessStrategy(final ValueModel domainObjectHolder, boolean fieldAccessEnabled, boolean strictNullValueHandling) {
087           super(domainObjectHolder);
088            propertyAccessor = new DefaultMemberPropertyAccessor(domainObjectHolder.getValue(), fieldAccessEnabled, strictNullValueHandling);
089        }
090    
091        /**
092         * Creates a child instance of <tt>ObjectPropertyAccessStrategy<tt>
093         * that will delegate to its parent for property access.
094         *
095         * @param parent <tt>ObjectPropertyAccessStrategy</tt> which will be used to provide property access
096         * @param basePropertyPath property path that will as a base when accessing
097         *                         the parent <tt>ObjectPropertyAccessStrategy</tt>
098         */
099        protected ObjectPropertyAccessStrategy(ObjectPropertyAccessStrategy parent, String basePropertyPath) {
100           super(parent, basePropertyPath);
101            propertyAccessor = parent.propertyAccessor;
102       }
103    
104        /**
105         * Provides <code>DefaultMemberPropertyAccessor</code> access to subclasses.
106         */
107        protected PropertyAccessor getPropertyAccessor() {
108           return propertyAccessor;
109        }
110    
111        public MutablePropertyAccessStrategy getPropertyAccessStrategyForPath(String propertyPath) throws BeansException {
112            return new ObjectPropertyAccessStrategy(this, getFullPropertyPath(propertyPath));
113        }
114    
115        public MutablePropertyAccessStrategy newPropertyAccessStrategy(ValueModel domainObjectHolder) {
116            return new ObjectPropertyAccessStrategy(domainObjectHolder);
117        }
118    
119        protected void domainObjectChanged() {
120           propertyAccessor.setTarget(getDomainObject());
121        }
122    }