001// --------------------------------------------------------------------------------
002// Copyright 2002-2026 Echo Three, LLC
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
017package com.echothree.view.client.web.struts;
018
019import com.echothree.control.user.core.common.CoreUtil;
020import com.echothree.control.user.core.common.form.ValidateForm;
021import com.echothree.control.user.core.common.result.ValidateResult;
022import com.echothree.model.data.user.common.pk.UserVisitPK;
023import com.echothree.util.common.validation.FieldDefinition;
024import com.echothree.util.common.form.BaseForm;
025import com.echothree.util.common.form.BaseFormFactory;
026import com.echothree.view.client.web.WebConstants;
027import com.echothree.view.client.web.taglib.TagConstants;
028import com.echothree.view.common.BaseChoicesBean;
029import java.lang.reflect.InvocationTargetException;
030import java.util.ArrayList;
031import java.util.HashMap;
032import java.util.List;
033import java.util.Map;
034import javax.naming.NamingException;
035import javax.servlet.http.HttpServletRequest;
036import org.apache.struts.action.ActionForm;
037import org.apache.struts.action.ActionMapping;
038import org.apache.struts.util.LabelValueBean;
039
040public class BaseActionForm
041        extends ActionForm {
042    
043    protected UserVisitPK userVisitPK;
044    private String dtIdAttribute;
045    private String dtSortParameter;
046    private String dtPageParameter;
047    private String dtOrderParameter;
048    private String submitButton;
049    
050    /** Creates a new instance of BaseActionForm */
051    public BaseActionForm() {
052        super();
053        
054        userVisitPK = null;
055    }
056    
057    public List<LabelValueBean> convertChoicesOrEmptyChoice(BaseChoicesBean choices) {
058        return choices == null ? List.of(new LabelValueBean("", "")) : convertChoices(choices);
059    }
060
061    public List<LabelValueBean> convertChoices(BaseChoicesBean choices) {
062        var labels = choices.getLabels();
063        var values = choices.getValues();
064        var labelsSize = labels.size();
065        var valuesSize = values.size();
066        List<LabelValueBean> result = null;
067        
068        if(labelsSize == valuesSize) {
069            result = new ArrayList<>(labelsSize);
070            var labelIterator = labels.iterator();
071            var valueIterator = values.iterator();
072            
073            while(labelIterator.hasNext() && valueIterator.hasNext()) {
074                var label = labelIterator.next();
075                var value = valueIterator.next();
076                
077                if(label == null)
078                    label = "";
079                
080                result.add(new LabelValueBean(label, value));
081            }
082        }
083        
084        return result;
085    }
086    
087    @Override
088    public void reset(ActionMapping mapping, HttpServletRequest request) {
089        super.reset(mapping, request);
090
091        var httpSession = request.getSession(true);
092        
093        userVisitPK = (UserVisitPK)httpSession.getAttribute(WebConstants.Session_USER_VISIT);
094    }
095
096    public String getDtIdAttribute() {
097        return dtIdAttribute;
098    }
099
100    public void setDtIdAttribute(String dtIdAttribute) {
101        this.dtIdAttribute = dtIdAttribute;
102    }
103
104    public String getDtSortParameter() {
105        return dtSortParameter;
106    }
107
108    public void setDtSortParameter(String dtSortParameter) {
109        this.dtSortParameter = dtSortParameter;
110    }
111
112    public String getDtPageParameter() {
113        return dtPageParameter;
114    }
115
116    public void setDtPageParameter(String dtPageParameter) {
117        this.dtPageParameter = dtPageParameter;
118    }
119
120    public String getDtOrderParameter() {
121        return dtOrderParameter;
122    }
123
124    public void setDtOrderParameter(String dtOrderParameter) {
125        this.dtOrderParameter = dtOrderParameter;
126    }
127    
128    public void saveDtParameters(HttpServletRequest request) {
129        dtIdAttribute = request.getParameter(WebConstants.Parameter_DT_ID_ATTRIBUTE);
130        dtSortParameter = request.getParameter(WebConstants.Parameter_DT_SORT_PARAMETER);
131        dtPageParameter = request.getParameter(WebConstants.Parameter_DT_PAGE_PARAMETER);
132        dtOrderParameter = request.getParameter(WebConstants.Parameter_DT_ORDER_PARAMETER);
133    }
134
135    public String getSubmitButton() {
136        return submitButton;
137    }
138
139    public void setSubmitButton(String submitButton) {
140        this.submitButton = submitButton;
141    }
142
143    private ValidateForm getValidateForm(final List<FieldDefinition> fieldDefinitions, final Map<String, Class> returnTypes)
144            throws NamingException {
145        var validateForm = CoreUtil.getHome().getValidateForm();
146        var baseForm = BaseFormFactory.createForm(BaseForm.class);
147        Class<?> clazz = this.getClass();
148
149        for(var fieldDefinition : fieldDefinitions) {
150            var fieldName = fieldDefinition.getFieldName();
151            
152            try {
153                var method = clazz.getMethod("get" + fieldName);
154                var fieldValue = method.invoke(this);
155
156                returnTypes.put(fieldName, method.getReturnType());
157
158                if(fieldValue != null) {
159                    baseForm.set(fieldName, fieldValue.toString());
160                }
161            } catch(NoSuchMethodException nsme) {
162                throw new RuntimeException(nsme);
163            } catch(IllegalAccessException iae) {
164                throw new RuntimeException(iae);
165            } catch(IllegalArgumentException iea) {
166                throw new RuntimeException(iea);
167            } catch(InvocationTargetException ite) {
168                throw new RuntimeException(ite);
169            }
170        }
171
172        validateForm.setFormFieldDefinitions(fieldDefinitions);
173        validateForm.setBaseForm(baseForm);
174
175        return validateForm;
176    }
177
178    private void setFormValidateResult(final ValidateResult validateResult, final Map<String, Class> returnTypes) {
179        var baseForm = validateResult.getBaseForm();
180        var map = baseForm.get();
181        Class<?> clazz = this.getClass();
182
183        for(var entry : map.entrySet()) {
184            var key = entry.getKey();
185            Class<?> returnType = returnTypes.get(key);
186
187            // If getValidateForm didn't add a map entry, returnType will be null. Ignore those
188            // values, as they tend to be from functions like getFomName() which don't exist on
189            // the ActionForm.
190            if(returnType != null) {
191                var methodName = "set" + key;
192                var value = entry.getValue();
193
194                if(returnType.equals(Boolean.class) && value instanceof String) {
195                    value = Boolean.valueOf((String)value);
196                } else if(returnType.equals(Integer.class) && value instanceof String) {
197                    value = Integer.valueOf((String)value);
198                } else if(returnType.equals(Long.class) && value instanceof String) {
199                    value = Long.valueOf((String)value);
200                }
201
202                try {
203                    clazz.getMethod(methodName, returnType).invoke(this, value);
204                } catch(NoSuchMethodException nsme) {
205                    throw new RuntimeException(nsme);
206                } catch(IllegalAccessException iae) {
207                    throw new RuntimeException(iae);
208                } catch(IllegalArgumentException iea) {
209                    throw new RuntimeException(iea);
210                } catch(InvocationTargetException ite) {
211                    throw new RuntimeException(ite);
212                }
213            }
214        }
215    }
216
217    protected boolean validate(final HttpServletRequest request, final List<FieldDefinition> fieldDefinitions)
218            throws NamingException {
219        Map<String, Class> returnTypes = new HashMap<>(fieldDefinitions.size());
220        var commandForm = getValidateForm(fieldDefinitions, returnTypes);
221
222        var commandResult = CoreUtil.getHome().validate(BaseAction.getUserVisitPK(request), commandForm);
223        if(!commandResult.hasErrors()) {
224            var executionResult = commandResult.getExecutionResult();
225
226            setFormValidateResult(executionResult.getResult(), returnTypes);
227        }
228
229        request.setAttribute(TagConstants.CommandResultName, commandResult);
230
231        return !commandResult.hasErrors();
232    }
233    
234}