001    /*
002     * Copyright 2002-2004 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.richclient.form.binding.support;
017    
018    import java.util.Arrays;
019    import java.util.Collections;
020    import java.util.HashSet;
021    import java.util.Iterator;
022    import java.util.Map;
023    import java.util.Set;
024    
025    import javax.swing.JComponent;
026    
027    import org.apache.commons.logging.Log;
028    import org.apache.commons.logging.LogFactory;
029    import org.springframework.binding.form.FormModel;
030    import org.springframework.richclient.application.support.ApplicationServicesAccessor;
031    import org.springframework.richclient.form.binding.Binder;
032    import org.springframework.richclient.form.binding.Binding;
033    import org.springframework.util.Assert;
034    
035    /**
036     * @author Oliver Hutchison
037     */
038    public abstract class AbstractBinder extends ApplicationServicesAccessor implements Binder {
039    
040        /**
041         * The client property key that is used to save a copy of a binding in its bound 
042         * component's client property set. This can be used to locate the binding 
043         * that has bound a given component.
044         * @see JComponent#getClientProperty(java.lang.Object)
045         */
046        public static final String BINDING_CLIENT_PROPERTY_KEY = "binding";
047    
048        protected final Log log = LogFactory.getLog(getClass());
049    
050        private final Class requiredSourceClass;
051    
052        private final Set supportedContextKeys;
053    
054        protected AbstractBinder(Class requiredSourceClass) {
055            this.requiredSourceClass = requiredSourceClass;
056            this.supportedContextKeys = Collections.EMPTY_SET;
057        }
058    
059        protected AbstractBinder(Class requiredSourceClass, String[] supportedContextKeys) {
060            this.requiredSourceClass = requiredSourceClass;
061            this.supportedContextKeys = new HashSet(Arrays.asList(supportedContextKeys));
062        }
063    
064        protected void validateContextKeys(Map context) {
065            Set unkownKeys = new HashSet(context.keySet());
066            unkownKeys.removeAll(supportedContextKeys);
067            for (Iterator i = unkownKeys.iterator(); i.hasNext();) {
068                final Object key = i.next();
069                context.remove(key);
070                if (log.isWarnEnabled()) {
071                    log.warn("Context key '" + key + "' not supported.");
072                }
073            }
074        }
075        
076        public Class getRequiredSourceClass() {
077            return requiredSourceClass;
078        }
079    
080        public Binding bind(FormModel formModel, String formPropertyPath, Map context) {
081            JComponent control = createControl(context);
082            Assert.notNull(control, "This binder does not support creating a default control.");
083            return bind(control, formModel, formPropertyPath, context);
084        }
085    
086        protected abstract JComponent createControl(Map context);
087    
088        public Binding bind(JComponent control, FormModel formModel, String formPropertyPath, Map context) {
089            // Ensure that this component has not already been bound
090            Binding binding = (Binding)control.getClientProperty(BINDING_CLIENT_PROPERTY_KEY);
091            if( binding != null ) {
092                throw new IllegalStateException( "Component is already bound to property: " + binding.getProperty());
093            }
094            validateContextKeys(context);
095            binding = doBind(control, formModel, formPropertyPath, context);
096            control.putClientProperty(BINDING_CLIENT_PROPERTY_KEY, binding);
097            return binding;
098        }
099    
100        protected abstract Binding doBind(JComponent control, FormModel formModel, String formPropertyPath, Map context);
101    
102        protected Class getPropertyType(FormModel formModel, String formPropertyPath) {
103            return formModel.getFieldMetadata(formPropertyPath).getPropertyType();
104        }
105    }