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.richclient.beans;
017
018 import org.springframework.beans.NullValueInNestedPathException;
019 import org.springframework.beans.PropertyAccessor;
020 import org.springframework.util.CachingMapDecorator;
021
022 /**
023 * This implementation extends {@link AbstractMemberPropertyAccessor} with the
024 * functionality of nested property handling.
025 *
026 * @author Arne Limburg
027 *
028 */
029 public abstract class AbstractNestedMemberPropertyAccessor extends AbstractMemberPropertyAccessor {
030
031 private AbstractNestedMemberPropertyAccessor parentPropertyAccessor;
032
033 private String basePropertyName;
034
035 private final ChildPropertyAccessorCache childPropertyAccessors = new ChildPropertyAccessorCache();
036
037 private final boolean strictNullHandlingEnabled;
038
039 protected AbstractNestedMemberPropertyAccessor(Class targetClass, boolean fieldAccessEnabled,
040 boolean strictNullHandlingEnabled) {
041 super(targetClass, fieldAccessEnabled);
042 this.strictNullHandlingEnabled = strictNullHandlingEnabled;
043 }
044
045 public AbstractNestedMemberPropertyAccessor(AbstractNestedMemberPropertyAccessor parent, String baseProperty) {
046 super(parent.getPropertyType(baseProperty), parent.isFieldAccessEnabled());
047 parentPropertyAccessor = parent;
048 basePropertyName = baseProperty;
049 strictNullHandlingEnabled = parent.strictNullHandlingEnabled;
050 }
051
052 public boolean isStrictNullHandlingEnabled() {
053 return strictNullHandlingEnabled;
054 }
055
056 protected AbstractNestedMemberPropertyAccessor getParentPropertyAccessor() {
057 return parentPropertyAccessor;
058 }
059
060 protected String getBasePropertyName() {
061 return basePropertyName;
062 }
063
064 public Object getTarget() {
065 if (parentPropertyAccessor != null && basePropertyName != null) {
066 return parentPropertyAccessor.getPropertyValue(basePropertyName);
067 }
068 else {
069 return null;
070 }
071 }
072
073 public Class getTargetClass() {
074 if (parentPropertyAccessor != null) {
075 return parentPropertyAccessor.getPropertyType(basePropertyName);
076 }
077 else {
078 return super.getTargetClass();
079 }
080 }
081
082 public boolean isReadableProperty(String propertyPath) {
083 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
084 String baseProperty = getBasePropertyName(propertyPath);
085 String childPropertyPath = getChildPropertyPath(propertyPath);
086 if (!super.isReadableProperty(baseProperty)) {
087 return false;
088 }
089 else {
090 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty))
091 .isReadableProperty(childPropertyPath);
092 }
093 }
094 else {
095 return super.isReadableProperty(propertyPath);
096 }
097 }
098
099 public boolean isWritableProperty(String propertyPath) {
100 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
101 String baseProperty = getBasePropertyName(propertyPath);
102 String childPropertyPath = getChildPropertyPath(propertyPath);
103 return super.isReadableProperty(baseProperty)
104 && ((PropertyAccessor) childPropertyAccessors.get(baseProperty))
105 .isWritableProperty(childPropertyPath);
106 }
107 else {
108 return super.isWritableProperty(propertyPath);
109 }
110 }
111
112 public Class getPropertyType(String propertyPath) {
113 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
114 String baseProperty = getBasePropertyName(propertyPath);
115 String childPropertyPath = getChildPropertyPath(propertyPath);
116 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyType(childPropertyPath);
117 }
118 else {
119 return super.getPropertyType(propertyPath);
120 }
121 }
122
123 public Object getPropertyValue(String propertyPath) {
124 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
125 String baseProperty = getBasePropertyName(propertyPath);
126 String childPropertyPath = getChildPropertyPath(propertyPath);
127 return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyValue(childPropertyPath);
128 }
129 else if (isStrictNullHandlingEnabled() && getTarget() == null) {
130 throw new NullValueInNestedPathException(getTargetClass(), propertyPath);
131 }
132 else {
133 return super.getPropertyValue(propertyPath);
134 }
135 }
136
137 public void setPropertyValue(String propertyPath, Object value) {
138 if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
139 String baseProperty = getBasePropertyName(propertyPath);
140 String childPropertyPath = getChildPropertyPath(propertyPath);
141 ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).setPropertyValue(childPropertyPath, value);
142 }
143 else if (isStrictNullHandlingEnabled() && getTarget() == null) {
144 throw new NullValueInNestedPathException(getTargetClass(), propertyPath);
145 }
146 else {
147 super.setPropertyValue(propertyPath, value);
148 }
149 }
150
151 protected String getBasePropertyName(String propertyPath) {
152 int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
153 return index == -1 ? propertyPath : propertyPath.substring(0, index);
154 }
155
156 protected String getChildPropertyPath(String propertyPath) {
157 int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
158 if (index == -1) {
159 return "";
160 }
161 return propertyPath.substring(index + 1);
162 }
163
164 protected PropertyAccessor getChildPropertyAccessor(String propertyName) {
165 return (PropertyAccessor) childPropertyAccessors.get(propertyName);
166 }
167
168 protected abstract AbstractNestedMemberPropertyAccessor createChildPropertyAccessor(String propertyName);
169
170 protected void clearChildPropertyAccessorCache() {
171 childPropertyAccessors.clear();
172 }
173
174 private class ChildPropertyAccessorCache extends CachingMapDecorator {
175
176 protected Object create(Object propertyName) {
177 return createChildPropertyAccessor((String) propertyName);
178 }
179 }
180 }