001    // Copyright Jul 30, 2006 The Apache Software Foundation
002    //
003    // Licensed under the Apache License, Version 2.0 (the "License");
004    // you may not use this file except in compliance with the License.
005    // 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
010    // distributed under the License is distributed on an "AS IS" BASIS,
011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012    // See the License for the specific language governing permissions and
013    // limitations under the License.
014    package org.apache.tapestry.dojo.form;
015    
016    import java.util.HashMap;
017    import java.util.List;
018    import java.util.Map;
019    
020    import org.apache.commons.beanutils.PropertyUtils;
021    import org.apache.hivemind.ApplicationRuntimeException;
022    import org.apache.hivemind.util.Defense;
023    
024    
025    /**
026     * Default simple implementation of {@link IAutocompleteModel}. This class relies
027     * on the java beans specification to resolve key fields of an incoming 
028     * {@link List}. 
029     * 
030     * <p>
031     *  If you had an object type of <code>User</code>, with the primary/unique id of 
032     *  each <code>User</code> object stored as a member with a name of <code>id</code> 
033     *  you would pass something like this into the model(don't forget that javabeans syntax
034     *  requires a corresponding getId() for members):
035     * </p>
036     * 
037     * <pre>
038     *  IAutocompleteModel model = new DefaultAutocompleteModel(List users, "id", "name");
039     * </pre>
040     * 
041     * @see {@linkplain http://jakarta.apache.org/commons/beanutils/commons-beanutils-1.6.1/docs/api/org/apache/commons/beanutils/PropertyUtils.html}
042     * @author jkuhnert
043     */
044    public class DefaultAutocompleteModel implements IAutocompleteModel
045    {
046    
047        private List _values;
048        
049        private String _keyExpression;
050        
051        private String _labelExpression;
052        
053        /**
054         * Create a new model using java beans syntax to access the key/label
055         * for the list using the specified bean expressions.
056         * 
057         * @param values 
058         *          The list of values to manage.
059         * @param keyField 
060         *          The java beans expression for getting the primary key of each object
061         *          in the list. {@link #getPrimaryKey(Object)}.
062         * @param labelField
063         *          The java beans expression for getting the label of each object
064         *          in the list. {@link #getLabelFor(Object)}.
065         */
066        public DefaultAutocompleteModel(List values, String keyField, String labelField) 
067        {
068            Defense.notNull(values, "Value list can't be null.");
069            Defense.notNull(keyField, "Model keyField java beans expression can't be null.");
070            Defense.notNull(labelField, "Model labelField java beans expression can't be null.");
071            
072            _values = values;
073            _keyExpression = keyField;
074            _labelExpression = labelField;
075        }
076        
077        /** 
078         * {@inheritDoc}
079         */
080        public Map filterValues(String match)
081        {
082            Map ret = new HashMap();
083            
084            if (match == null)
085                return ret;
086            
087            String filter = match.trim().toLowerCase();
088            
089            for (int i = 0; i < _values.size(); i++) {
090                
091                Object value = _values.get(i);
092                String label = getLabelFor(value);
093                
094                if (label.toLowerCase().indexOf(filter) > -1)
095                    ret.put(getPrimaryKey(value), label);
096            }
097            
098            return ret;
099        }
100        
101        /** 
102         * {@inheritDoc}
103         */
104        public String getLabelFor(Object value)
105        {
106            try {
107                
108                return PropertyUtils.getProperty(value, _labelExpression).toString();
109                
110            } catch (Exception e) {
111                throw new ApplicationRuntimeException(e);
112            }
113        }
114    
115        /** 
116         * {@inheritDoc}
117         */
118        public Object getPrimaryKey(Object value)
119        {
120            try {
121                
122                return PropertyUtils.getProperty(value, _keyExpression);
123                
124            } catch (Exception e) {
125                throw new ApplicationRuntimeException(e);
126            }
127        }
128    
129        /** 
130         * {@inheritDoc}
131         */
132        public Object getValue(Object primaryKey)
133        {
134            for (int i = 0; i < _values.size(); i++) {
135                
136                Object value = _values.get(i);
137                if (getPrimaryKey(value).toString().equals(primaryKey.toString()))
138                    return value;
139            }
140            
141            return null;
142        }
143    
144    }