001    // Copyright 2006, 2007, 2008, 2009 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    
015    package org.apache.tapestry5.corelib.internal;
016    
017    import org.apache.tapestry5.ComponentAction;
018    import org.apache.tapestry5.ComponentResources;
019    import org.apache.tapestry5.Field;
020    import org.apache.tapestry5.ioc.Locatable;
021    import org.apache.tapestry5.ioc.Location;
022    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
023    import org.apache.tapestry5.ioc.internal.util.Defense;
024    import org.apache.tapestry5.ioc.internal.util.IdAllocator;
025    import org.apache.tapestry5.services.ClientBehaviorSupport;
026    
027    import java.util.List;
028    
029    /**
030     * Provides support to components enclosed by a form when the form is rendering (allowing the components to registry
031     * form submit callback commands), and also during form submission time.
032     * <p/>
033     * TODO: Most methods should only be invokable depending on whether the form is rendering or processing a submission.
034     */
035    public class FormSupportImpl implements InternalFormSupport, Locatable
036    {
037        private final ComponentResources resources;
038    
039        private final ClientBehaviorSupport clientBehaviorSupport;
040    
041        private final boolean clientValidationEnabled;
042    
043        private final IdAllocator idAllocator;
044    
045        private final String clientId;
046    
047        private final ComponentActionSink actionSink;
048    
049        private final String formValidationId;
050    
051        private List<Runnable> commands;
052    
053        private String encodingType;
054    
055        /**
056         * Constructor used when processing a form submission.
057         */
058        public FormSupportImpl(ComponentResources resources, String formValidationId)
059        {
060            this(resources, null, null, null, false, null, formValidationId);
061        }
062    
063        /**
064         * Full constructor (specifically constructor for render time).
065         */
066        public FormSupportImpl(ComponentResources resources, String clientId, ComponentActionSink actionSink,
067                               ClientBehaviorSupport clientBehaviorSupport,
068                               boolean clientValidationEnabled, IdAllocator idAllocator, String formValidationId)
069        {
070            this.resources = resources;
071            this.clientId = clientId;
072            this.actionSink = actionSink;
073            this.clientBehaviorSupport = clientBehaviorSupport;
074            this.clientValidationEnabled = clientValidationEnabled;
075            this.idAllocator = idAllocator;
076            this.formValidationId = formValidationId;
077        }
078    
079        public Location getLocation()
080        {
081            return resources.getLocation();
082        }
083    
084        public String getFormComponentId()
085        {
086            return resources.getCompleteId();
087        }
088    
089        public String allocateControlName(String id)
090        {
091            return idAllocator.allocateId(id);
092        }
093    
094        public <T> void store(T component, ComponentAction<T> action)
095        {
096            actionSink.store(component, action);
097        }
098    
099        public <T> void storeAndExecute(T component, ComponentAction<T> action)
100        {
101            actionSink.store(component, action);
102    
103            action.execute(component);
104        }
105    
106        public void defer(Runnable command)
107        {
108            if (commands == null) commands = CollectionFactory.newList();
109    
110            commands.add(Defense.notNull(command, "command"));
111        }
112    
113        public void executeDeferred()
114        {
115            if (commands == null) return;
116    
117            for (Runnable r : commands)
118                r.run();
119    
120            commands.clear();
121        }
122    
123        public String getClientId()
124        {
125            return clientId;
126        }
127    
128        public String getEncodingType()
129        {
130            return encodingType;
131        }
132    
133        public void setEncodingType(String encodingType)
134        {
135            Defense.notBlank(encodingType, "encodingType");
136    
137            if (this.encodingType != null && !this.encodingType.equals(encodingType))
138                throw new IllegalStateException(InternalMessages.conflictingEncodingType(this.encodingType, encodingType));
139    
140            this.encodingType = encodingType;
141        }
142    
143        public void addValidation(Field field, String validationName, String message, Object constraint)
144        {
145            if (clientValidationEnabled)
146                clientBehaviorSupport.addValidation(field, validationName, message, constraint);
147        }
148    
149        public boolean isClientValidationEnabled()
150        {
151            return clientValidationEnabled;
152        }
153    
154        public String getFormValidationId()
155        {
156            return formValidationId;
157        }
158    }