/*
* Copyright 2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package org.springframework.richclient.beans;
import org.springframework.beans.NullValueInNestedPathException;
import org.springframework.beans.PropertyAccessor;
import org.springframework.util.CachingMapDecorator;
/**
* This implementation extends {@link AbstractMemberPropertyAccessor} with the
* functionality of nested property handling.
*
* @author Arne Limburg
*
*/
public abstract class AbstractNestedMemberPropertyAccessor extends AbstractMemberPropertyAccessor {
private AbstractNestedMemberPropertyAccessor parentPropertyAccessor;
private String basePropertyName;
private final ChildPropertyAccessorCache childPropertyAccessors = new ChildPropertyAccessorCache();
private final boolean strictNullHandlingEnabled;
protected AbstractNestedMemberPropertyAccessor(Class targetClass, boolean fieldAccessEnabled,
boolean strictNullHandlingEnabled) {
super(targetClass, fieldAccessEnabled);
this.strictNullHandlingEnabled = strictNullHandlingEnabled;
}
public AbstractNestedMemberPropertyAccessor(AbstractNestedMemberPropertyAccessor parent, String baseProperty) {
super(parent.getPropertyType(baseProperty), parent.isFieldAccessEnabled());
parentPropertyAccessor = parent;
basePropertyName = baseProperty;
strictNullHandlingEnabled = parent.strictNullHandlingEnabled;
}
public boolean isStrictNullHandlingEnabled() {
return strictNullHandlingEnabled;
}
protected AbstractNestedMemberPropertyAccessor getParentPropertyAccessor() {
return parentPropertyAccessor;
}
protected String getBasePropertyName() {
return basePropertyName;
}
public Object getTarget() {
if (parentPropertyAccessor != null && basePropertyName != null) {
return parentPropertyAccessor.getPropertyValue(basePropertyName);
}
else {
return null;
}
}
public Class getTargetClass() {
if (parentPropertyAccessor != null) {
return parentPropertyAccessor.getPropertyType(basePropertyName);
}
else {
return super.getTargetClass();
}
}
public boolean isReadableProperty(String propertyPath) {
if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
String baseProperty = getBasePropertyName(propertyPath);
String childPropertyPath = getChildPropertyPath(propertyPath);
if (!super.isReadableProperty(baseProperty)) {
return false;
}
else {
return ((PropertyAccessor) childPropertyAccessors.get(baseProperty))
.isReadableProperty(childPropertyPath);
}
}
else {
return super.isReadableProperty(propertyPath);
}
}
public boolean isWritableProperty(String propertyPath) {
if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
String baseProperty = getBasePropertyName(propertyPath);
String childPropertyPath = getChildPropertyPath(propertyPath);
return super.isReadableProperty(baseProperty)
&& ((PropertyAccessor) childPropertyAccessors.get(baseProperty))
.isWritableProperty(childPropertyPath);
}
else {
return super.isWritableProperty(propertyPath);
}
}
public Class getPropertyType(String propertyPath) {
if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
String baseProperty = getBasePropertyName(propertyPath);
String childPropertyPath = getChildPropertyPath(propertyPath);
return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyType(childPropertyPath);
}
else {
return super.getPropertyType(propertyPath);
}
}
public Object getPropertyValue(String propertyPath) {
if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
String baseProperty = getBasePropertyName(propertyPath);
String childPropertyPath = getChildPropertyPath(propertyPath);
return ((PropertyAccessor) childPropertyAccessors.get(baseProperty)).getPropertyValue(childPropertyPath);
}
else if (isStrictNullHandlingEnabled() && getTarget() == null) {
throw new NullValueInNestedPathException(getTargetClass(), propertyPath);
}
else {
return super.getPropertyValue(propertyPath);
}
}
public void setPropertyValue(String propertyPath, Object value) {
if (PropertyAccessorUtils.isNestedProperty(propertyPath)) {
String baseProperty = getBasePropertyName(propertyPath);
String childPropertyPath = getChildPropertyPath(propertyPath);
((PropertyAccessor) childPropertyAccessors.get(baseProperty)).setPropertyValue(childPropertyPath, value);
}
else if (isStrictNullHandlingEnabled() && getTarget() == null) {
throw new NullValueInNestedPathException(getTargetClass(), propertyPath);
}
else {
super.setPropertyValue(propertyPath, value);
}
}
protected String getBasePropertyName(String propertyPath) {
int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
return index == -1 ? propertyPath : propertyPath.substring(0, index);
}
protected String getChildPropertyPath(String propertyPath) {
int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(propertyPath);
if (index == -1) {
return "";
}
return propertyPath.substring(index + 1);
}
protected PropertyAccessor getChildPropertyAccessor(String propertyName) {
return (PropertyAccessor) childPropertyAccessors.get(propertyName);
}
protected abstract AbstractNestedMemberPropertyAccessor createChildPropertyAccessor(String propertyName);
protected void clearChildPropertyAccessorCache() {
childPropertyAccessors.clear();
}
private class ChildPropertyAccessorCache extends CachingMapDecorator {
protected Object create(Object propertyName) {
return createChildPropertyAccessor((String) propertyName);
}
}
}