001: /*
002: * Copyright 2005-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005: * in compliance with the License. You may obtain a copy of the License at
006: *
007: * http://www.apache.org/licenses/LICENSE-2.0
008: *
009: * Unless required by applicable law or agreed to in writing, software distributed under the License
010: * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011: * or implied. See the License for the specific language governing permissions and limitations under
012: * the License.
013: */
014:
015: package org.strecks.bind.handler;
016:
017: import java.util.Collection;
018: import java.util.HashMap;
019: import java.util.Map;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023: import org.strecks.converter.ConversionState;
024: import org.strecks.exceptions.ApplicationRuntimeException;
025: import org.strecks.util.Assert;
026: import org.strecks.util.PropertyValueGetter;
027: import org.strecks.util.PropertyValueSetter;
028:
029: /**
030: * <p>
031: * Adds support for binding a selection, represented by a String scalar ID value, to an object.
032: * </p>
033: * <p>
034: * For example suppose you want to select male or female, each represented by an instance of Gender,
035: * to a Person object. The form will receive a "gender id" representing a gender. This id needs to
036: * be type converted (for example to an Integer), then used to lookup the actual Gender object. This
037: * Gender object is then itself bound to a target object. The mechanism can be applied for radio
038: * buttons, single value check boxes, and drop down lists.
039: * </p>
040: * @see org.strecks.bind.annotations.BindSelect
041: *
042: * @author Phil Zoio
043: */
044: public class BindSelectHandler extends AbstractBindHandler implements
045: BindHandler {
046:
047: private static Log log = LogFactory.getLog(BindSelectHandler.class);
048:
049: /**
050: * holds the expression of the bean to set (eg. person.gender)
051: */
052: private String targetBeanExpression;
053:
054: /**
055: * holds the expression of the target bean to set (eg. person)
056: */
057: private String beanLocatingExpression;
058:
059: /**
060: * the property for the bean part of target bean to (eg. the gender part of person.gender.id)
061: */
062: private String beanPropertyName;
063:
064: /**
065: * the property for the id part of target bean to (eg. the gender part of person.gender.id)
066: */
067: private String beanPropertyIdName;
068:
069: /**
070: * the expression to the map containing the lookups for the person
071: */
072: private String beanLookupExpression;
073:
074: /**
075: * the class of the id
076: */
077: private Class beanPropertyClass;
078:
079: public void bindInwards(Object form, Object actionBean,
080: Object convertedValue) {
081:
082: checkInwardState();
083:
084: Object targetBean = PropertyValueGetter.getTargetBean(form,
085: getBeanLocatingExpression());
086:
087: if (targetBean != null) {
088:
089: Object idValue = null;
090:
091: if (convertedValue == null
092: || convertedValue == ConversionState.FAILURE) {
093: idValue = getAndConvertInwards(form,
094: getPropertyDescriptor().getName(), this
095: .getConverter());
096: } else if (convertedValue == ConversionState.NULL) {
097: idValue = null;
098: } else {
099: //use converted value if already available
100: idValue = convertedValue;
101: }
102:
103: // now get corresponding value from map
104: Object property = PropertyValueGetter.getPropertyValue(
105: form, getBeanLookupExpression());
106:
107: Map map = getPropertyAsMap(property);
108:
109: if (map != null) {
110:
111: Object mappedValue = map.get(idValue);
112:
113: if (mappedValue == null) {
114: if (log.isDebugEnabled()) {
115: log.debug("No object found in map "
116: + form.getClass().getName()
117: + " using epxression "
118: + getBeanLookupExpression()
119: + " using id " + idValue);
120: }
121: }
122:
123: PropertyValueSetter.setPropertyValue(targetBean, this
124: .getBeanPropertyName(), getBeanPropertyClass(),
125: mappedValue);
126:
127: } else {
128: log.warn("Map not found for bean "
129: + form.getClass().getName()
130: + " using epxression "
131: + getBeanLookupExpression());
132: }
133:
134: }
135: }
136:
137: public void bindOutwards(Object source, Object target) {
138:
139: checkOutwardState();
140:
141: Object targetBean = PropertyValueGetter.getTargetBean(source,
142: getBeanLocatingExpression());
143:
144: if (targetBean != null) {
145:
146: Object selectedObject = PropertyValueGetter
147: .getPropertyValue(targetBean, this
148: .getBeanPropertyName());
149:
150: if (selectedObject != null) {
151: Object idValue = getAndConvertOutwards(selectedObject,
152: this .getBeanPropertyIdName(), this
153: .getConverter());
154: PropertyValueSetter.setPropertyValue(source,
155: getPropertyDescriptor(), idValue);
156: } else {
157: PropertyValueSetter.setPropertyValue(source,
158: getPropertyDescriptor(), null);
159: }
160:
161: }
162:
163: }
164:
165: Map getPropertyAsMap(Object property) {
166: Map map = null;
167: if (property instanceof Map) {
168: map = (Map) property;
169: } else {
170: if (property instanceof Collection) {
171: Collection collection = (Collection) property;
172: map = createMap(collection);
173: // CollectionUtils.getMap(collection);
174: } else if (property != null) {
175: throw new ApplicationRuntimeException(
176: "Property "
177: + getBeanLookupExpression()
178: + " should evaluate to a java.util.Map or java.util.Collection, not a "
179: + property.getClass().getName());
180: }
181: }
182: return map;
183: }
184:
185: private void checkInwardState() {
186: Assert.notNull(targetBeanExpression);
187: Assert.notNull(beanLocatingExpression);
188: Assert.notNull(beanPropertyIdName);
189: Assert.notNull(beanLookupExpression);
190: Assert.notNull(beanPropertyName);
191: Assert.notNull(beanPropertyClass);
192: Assert.notNull(getConversionHandler());
193: Assert.notNull(getConverter());
194: }
195:
196: private void checkOutwardState() {
197: Assert.notNull(beanLocatingExpression);
198: Assert.notNull(beanPropertyIdName);
199: Assert.notNull(beanPropertyName);
200: Assert.notNull(beanPropertyClass);
201: Assert.notNull(getPropertyDescriptor());
202: Assert.notNull(getConversionHandler());
203: Assert.notNull(getConverter());
204: }
205:
206: Map createMap(Collection collection) {
207: Map map;
208: map = new HashMap();
209:
210: for (Object item : collection) {
211: addItem(map, item);
212: }
213: return map;
214: }
215:
216: @SuppressWarnings("unchecked")
217: private void addItem(Map map, Object item) {
218: Object itemId = PropertyValueGetter.getPropertyValue(item,
219: beanPropertyIdName);
220: map.put(itemId, item);
221: }
222:
223: /* **** getter and setters ****** */
224:
225: public String getBeanLocatingExpression() {
226: return beanLocatingExpression;
227: }
228:
229: public void setBeanLocatingExpression(String beanLocatingExpression) {
230: this .beanLocatingExpression = beanLocatingExpression;
231: //FIXME set target source property
232: }
233:
234: public String getBeanLookupExpression() {
235: return beanLookupExpression;
236: }
237:
238: public void setBeanLookupExpression(String beanLookupExpression) {
239: this .beanLookupExpression = beanLookupExpression;
240: //FIXME set target source property
241: }
242:
243: public Class getBeanPropertyClass() {
244: return beanPropertyClass;
245: }
246:
247: public void setBeanPropertyClass(Class beanPropertyClass) {
248: this .beanPropertyClass = beanPropertyClass;
249: }
250:
251: public String getBeanPropertyName() {
252: return beanPropertyName;
253: }
254:
255: public void setBeanPropertyName(String beanPropertyName) {
256: this .beanPropertyName = beanPropertyName;
257: }
258:
259: public String getTargetBeanExpression() {
260: return targetBeanExpression;
261: }
262:
263: public void setTargetBeanExpression(String targetBeanExpression) {
264: this .targetBeanExpression = targetBeanExpression;
265: //FIXME set target source property
266: }
267:
268: public String getBeanPropertyIdName() {
269: return beanPropertyIdName;
270: }
271:
272: public void setBeanPropertyIdName(String beanPropertyIdName) {
273: this.beanPropertyIdName = beanPropertyIdName;
274: }
275:
276: }
|