001 /* 002 * Copyright 2002-2005 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of 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, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.springframework.binding.value.support; 017 018 import java.beans.PropertyChangeEvent; 019 import java.beans.PropertyChangeListener; 020 021 import org.springframework.binding.value.DerivedValueModel; 022 import org.springframework.binding.value.ValueModel; 023 024 /** 025 * Abstract base class for value models that derive their value from one or more 026 * "source" value model. Provides a hook to notify when any of the "source" 027 * value models change. 028 * 029 * @author Oliver Hutchison 030 */ 031 public abstract class AbstractDerivedValueModel extends AbstractValueModel implements DerivedValueModel { 032 033 private final ValueModel[] sourceValueModels; 034 035 private final PropertyChangeListener sourceChangeHandler; 036 037 /** 038 * Create a derivedValueModel based on the given sourceValueModels. When any 039 * of these valueModels has their value changed, the derivedValueModel will 040 * update its value. 041 * 042 * @param sourceValueModels an <code>Array</code> of valueModels that 043 * influence the derived value. 044 */ 045 protected AbstractDerivedValueModel(ValueModel[] sourceValueModels) { 046 this.sourceValueModels = sourceValueModels; 047 this.sourceChangeHandler = new PropertyChangeListener() { 048 049 public void propertyChange(PropertyChangeEvent evt) { 050 sourceValuesChanged(); 051 } 052 }; 053 for (int i = 0; i < sourceValueModels.length; i++) { 054 sourceValueModels[i].addValueChangeListener(sourceChangeHandler); 055 } 056 } 057 058 public ValueModel[] getSourceValueModels() { 059 return sourceValueModels; 060 } 061 062 /** 063 * Convenience method to extract values from all sourceValueModels that 064 * influence the derived value. 065 * 066 * @return an <code>Array</code> containing the source values in the same 067 * order as the source valueModels were defined. 068 */ 069 protected Object[] getSourceValues() { 070 Object[] values = new Object[sourceValueModels.length]; 071 for (int i = 0; i < values.length; i++) { 072 values[i] = sourceValueModels[i].getValue(); 073 } 074 return values; 075 } 076 077 /** 078 * Derive the value from the source values and fire a valueChangeEvent to 079 * notify listeners. 080 */ 081 protected abstract void sourceValuesChanged(); 082 083 /** 084 * A derived valueModel is always readOnly. 085 * 086 * @see #setValue(Object) 087 */ 088 public boolean isReadOnly() { 089 return true; 090 } 091 092 /** 093 * A {@link DerivedValueModel}'s value is based on other valueModels, it 094 * cannot be set. Will throw an {@link UnsupportedOperationException} when 095 * used. 096 */ 097 public void setValue(Object newValue) { 098 throw new UnsupportedOperationException("This value model is read only"); 099 } 100 }