001    // Copyright 2006, 2007, 2008, 2009, 2010 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 java.util.List;
018    
019    import org.apache.tapestry5.ComponentAction;
020    import org.apache.tapestry5.ComponentResources;
021    import org.apache.tapestry5.Field;
022    import org.apache.tapestry5.ioc.Locatable;
023    import org.apache.tapestry5.ioc.Location;
024    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
025    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
026    import org.apache.tapestry5.ioc.util.IdAllocator;
027    import org.apache.tapestry5.services.ClientBehaviorSupport;
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, boolean clientValidationEnabled, IdAllocator idAllocator,
068                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            assert command != null;
109    
110            if (commands == null)
111                commands = CollectionFactory.newList();
112    
113            commands.add(command);
114        }
115    
116        public void executeDeferred()
117        {
118            if (commands == null)
119                return;
120    
121            for (Runnable r : commands)
122                r.run();
123    
124            commands.clear();
125        }
126    
127        public String getClientId()
128        {
129            return clientId;
130        }
131    
132        public String getEncodingType()
133        {
134            return encodingType;
135        }
136    
137        public void setEncodingType(String encodingType)
138        {
139            assert InternalUtils.isNonBlank(encodingType);
140    
141            if (this.encodingType != null && !this.encodingType.equals(encodingType))
142                throw new IllegalStateException(InternalMessages.conflictingEncodingType(this.encodingType, encodingType));
143    
144            this.encodingType = encodingType;
145        }
146    
147        public void addValidation(Field field, String validationName, String message, Object constraint)
148        {
149            if (clientValidationEnabled)
150                clientBehaviorSupport.addValidation(field, validationName, message, constraint);
151        }
152    
153        public boolean isClientValidationEnabled()
154        {
155            return clientValidationEnabled;
156        }
157    
158        public String getFormValidationId()
159        {
160            return formValidationId;
161        }
162    }