public class AttributeUtils {


	public static String buildAttributes(Map<String, String> attributes) {
		StringBuilder attrStr = new StringBuilder();
		attributes.forEach((k,v) ->
			attrStr.append(AttributeUtils.buildSingleAttribute(k, attributes.get(k)))
				);
		return attrStr.toString();
	}

	public static String buildSingleAttribute(String key, String value) {
		StringBuilder attrStr = new StringBuilder();
		if (StringUtils.isEmpty(value)) {
			attrStr.append(key);
		} else {
			attrStr.append(key).append("=\"").append(value).append("\"");
		}
		attrStr.append(" ");
		return attrStr.toString();
	}

	public static String buildAttributes(TagAttributes attributes) {
		return AttributeUtils.buildAttributes(attributes.attributes);
	}
} @FunctionalInterface
public interface Criterion {
	/**
	 * Tests whether the specified value satisfies this criterion.
	 * 
	 * @param value
	 *            to be tested against this criterion.
	 * @return a ValidationResult which holds true or false for validaton result
	 *         and a potential errormsg
	 */
	public ValidationResult validate(FormCheckerElement value);

} public class FormChecker {
	Request req;
	boolean firstRun = true;
	boolean isValid = true;
	FormCheckerForm form = null;
	Validator validator = new DefaultValidator();

	@Deprecated
	String id;

	/**
	 * Maximal lenght of input vars to avoid too long requests If you want to
	 * get longer element-vals, override it for each element!
	 */
	int defaultMaxLenElements = 1000;

	FormCheckerConfig config;

	String formAction = "#";

	// holds temporaryly config-infos while construction-process of fc
	private GenericFormBuilder tempFormBuilder;
	private MessageSource tempProperties;

	public static final String SUBMIT_KEY = "submitted";
	public static final String SUBMIT_VALUE_PREFIX = "FORMCHECKER-";

	/**
	 * Deprecated: Put id into the FormcheckerForm and use build(request, form)
	 * or Formchecker(request)
	 * 
	 * @param _id
	 * @param request
	 */
	@Deprecated
	public FormChecker(String _id, Request request) {
		id = _id;
		req = request;
	}

	public FormChecker(Request request) {
		req = request;
	}

	/**
	 * Deprecated: Use build(Request _req, FormCheckerForm form) and put id into
	 * the FormCheckerForm
	 * 
	 * @param _id
	 * @param _req
	 * @param form
	 * @return
	 */
	@Deprecated
	public static FormChecker build(String _id, Request _req, FormCheckerForm form) {
		FormChecker fc = new FormChecker(_id, _req);
		fc.id = _id;
		fc.addForm(form);
		return fc;
	}

	public static FormChecker build(Request _req, FormCheckerForm form) {
		FormChecker fc = new FormChecker(_req);
		fc.addForm(form);
		return fc;
	}

	public FormChecker setProtectAgainstCSRF(SessionGet sessionGet, SessionSet sessionSet) {
		if (form == null) {
			throw new IllegalArgumentException("Set the FormcheckerForm BEFORE calling setAgainstCSRF");
		}
		form.setProtectedAgainstCSRF(true);
		form.setSessionGet(sessionGet);
		form.setSessionSet(sessionSet);
		return this;
	}

	public FormChecker setConfig(FormCheckerConfig config) {
		this.config = config;
		return this;
	}

	public boolean isValid() {
		return isValid;
	}

	public boolean isValidAndNotFirstRun() {
		return isValid && !firstRun;
	}

	public FormCheckerForm getForm() {
		return form;
	}

	
	private GenericFormBuilder getFormBuilder() {
		return config.getFormBuilder();
	}

	public FormChecker setFormBuilder(GenericFormBuilder formBuilder) {
		this.tempFormBuilder = formBuilder;
		return this;
	}

	public FormChecker setProperties(MessageSource properties) {
		this.tempProperties = properties;
		return this;
	}


	public String getValue(String elementName) {
		return form.getElement(elementName).getValue();
	}




	/**
	 * Get the view for displaying html in the template
	 * 
	 * @return
	 */
	public View getView() {
		return new View(form, this.getFormBuilder(), this);
	}

	/**
	 * Get the view for displaying html in the template
	 * 
	 * @return
	 */
	@Deprecated
	public View getViewWithAccessObjects() {
		return new View(form, this.getFormBuilder(), this).generateAccessObjects();
	}

	
	public void setFormAction(String formAction) {
		this.formAction = formAction;
	}

	private void prepareElement(FormCheckerElement element) {
		element.setFormChecker(this);

		// check, if maxLen is set. If not, add default-max-len
		// defaultMaxLenElements;
		boolean maxLenAvail = false;

		for (Criterion criterion : element.getCriteria()) {
			if (criterion instanceof MaxLength) {
				maxLenAvail = true;
			}
		}
		if (!maxLenAvail) {
			element.getCriteria().add(Criteria.maxLength(defaultMaxLenElements));
		}
	}

	public void addForm(FormCheckerForm form) {
		this.form = form;
		if (id != null) { // Internal id overrides id from form
			form.setId(id);
		}
	}

	private String getGenericForm() {
		return config.getFormBuilder().generateGenericForm(formAction, firstRun, form, req, config.properties);
	}

	// move to ViewFacade
	public String getLabelForElement(FormCheckerElement e, Map<String, String> attribs) {
		return config.getFormBuilder().getLabelForElement(e, new TagAttributes(attribs), firstRun);
	}

	public FormChecker run() {

		setupConfig();

		sortTabIndexes();

		initForm();

		checkIfFirstRun();

		processAndValidateElements();

		validateCompleteForm();

		return this;
	}

	private void validateCompleteForm() {
		if (!firstRun) {
			for (FormValidator formValidator : form.getValidators()) {
				if (formValidator.validate(form) == false) {
					isValid = false;
					// continue loop here, because other FormValidators can set
					// manually errors on vields
				}
			}
		}
	}

	private void processAndValidateElements() {
		for (FormCheckerElement elem : form.getElements()) {
			elem.init(req, firstRun, validator);
			if (!elem.isValid()) {
				isValid = false;
			}
		}
	}

	private void initForm() {
		form.setMessageSource(this.getConfig().getProperties());
		form.init();

		for (FormCheckerElement element : form.getElements()) {
			prepareElement(element);
		}

	}

	/**
	 * set up the config-object for formchecker (handles absence of properties
	 * and formBuider)
	 */
	private void setupConfig() {
		if (config == null) {
			if (tempFormBuilder == null) {
				tempFormBuilder = new BasicFormBuilder();
			}
			if (tempProperties == null) {
				tempProperties = new MinimalMessageSource();
			}
			config = new FormCheckerConfig(tempProperties, tempFormBuilder);
		}
	}

	// resort tab-indexes
	private void sortTabIndexes() {
		int tabIndex = 100;
		for (FormCheckerElement elem : form.getElements()) {
			elem.setTabIndex(tabIndex);
			tabIndex = elem.getLastTabIndex();
			tabIndex++;
		}
	}

	private void checkIfFirstRun() {
		if ((FormChecker.SUBMIT_VALUE_PREFIX + form.getId()).equals(req.getParameter(FormChecker.SUBMIT_KEY))) {
			firstRun = false;
		}
	}

	// move to ViewFacade
	public String getCompleteForm() {
		return this.getGenericForm();
	}

	public FormCheckerConfig getConfig() {
		return config;
	}
} public interface FormCheckerElement {

	// RFE: check, if some methods can be protected

	// get internal name of this input-element
	public String getName();
	
	// set internal name
	public void setName(String name);


	// get the value that the user entered
	public String getValue();

	// get the value that the user entered, but html-encoded
	@Deprecated
	public String getValueHtmlEncoded();

	public void setValue(String value);

	public String getPreSetValue();

	// set an initial value to the element, before the user edited it.
	public <T extends FormCheckerElement> T setPreSetValue(String value);

	public <T extends FormCheckerElement> T setTabIndex(int tabIndex);

	public int getTabIndex();

	public int getLastTabIndex();

	// set the test in the label (builder pattern)
	
	public <T extends FormCheckerElement> T setDescription(String desc);

	// as "setDescription" but does not return anything (no builder pattern)
	public void changeDescription(String desc);

	public String getDescription();

	// returns true if element is valid
	public boolean isValid();

	public void setInvalid();

	// inits the value with the current http-request
	public void init(Request req, boolean firstrun, Validator validator);

	public ValidationResult getValidationResult();

	public void setValidationResult(ValidationResult validationResult);

	public String getInputTag();

	public String getInputTag(Map<String, String> attributes, MessageSource messageSource, boolean html5Validation);
	
	@Deprecated
	public String getInputTag(Map<String, String> attributes);

	public boolean isRequired();

	public <T extends FormCheckerElement> T setRequired();

	public List<Criterion> getCriteria();

	public void setFormChecker(FormChecker fc);

	// returns the complete label-html tag
	public String getLabel();

	// returns the label-html and the input-html
	public String getCompleteInput(); // RFE: Perhaps toString makes this even
										// more convenient?!

	public String getHelpText();

	// sets the size attribute
	public <T extends FormCheckerElement> T setSize(int size);

	public String getType();

} public class StringUtils {

  public static final String EMPTY_STR = "";

  public static boolean isEmpty(final CharSequence cs) {
    return cs == null || cs.length() == 0;
  }

  public static String defaultString(final String str) {
    return alternative(str, EMPTY_STR);
  }

  /**
   * checks if the original string is empty. if empty/null return the alternative, otherwise the
   * original
   * 
   * @param original
   * @param alternative
   * @return
   */
  public static String alternative(final String original, final String alternative) {
    return isEmpty(original) ? alternative : original;
  }


} public class TagAttributes {
	
	// conveniance methods
	public static TagAttributes of(String key, String value) {
		return new TagAttributes(key, value);
	}
	
	public static TagAttributes of(Map<String, String> attribs) {
		return new TagAttributes(attribs);
	}
	
	LinkedHashMap<String, String> attributes;

	public TagAttributes(Map<String, String> attribs) {
		attributes = new LinkedHashMap<>(attribs);
	}

	public TagAttributes(LinkedHashMap<String, String> attribs) {
		attributes = attribs;
	}

	public TagAttributes() {
		this(new LinkedHashMap<>());
	}

	public TagAttributes(String key, String value) {
		this();
		this.put(key, value);
	}

	public TagAttributes put(String key, String value) {
		attributes.put(key, value);
		return this;
	}

	public String get(String key) {
		return attributes.get(key);
	}

	public void addToAttribute(String key, String value) {
		if (!attributes.containsKey(key)) {
			attributes.put(key, value);
		} else {
			attributes.put(key, attributes.get(key) + value);
		}
	}

	public Set<String> keySet() {
		return attributes.keySet();
	}
	
	public Map<String, String> getAttributes() {
		return attributes;
	}

	public void add(TagAttributes formAttributes) {
		if (formAttributes != null) {
			formAttributes.attributes.forEach((key, value) -> this.addToAttribute(key, value));
		}
	}

	public void add(LinkedHashMap<String, String> attribs) {
		if (attribs != null) {
			attribs.forEach((key, value) -> this.addToAttribute(key, value));
		}
	}

} public final class MaxLength implements Criterion {
	private int maxLength;

	MaxLength(int maxLength) {
		this.maxLength = maxLength;
	}

	public int getMaxLength() {
		return maxLength;
	}

	@Override
	public ValidationResult validate(FormCheckerElement value) {
		boolean isValid = value.getValue().length() <= maxLength;
		if (!isValid) {
			return ValidationResult.fail("jformchecker.max_len", maxLength);
		}
		return ValidationResult.ok();
	}

} public class ValidationResult {

	boolean isValid = false;
	
	// caching:
	private static ValidationResult okResult =  new ValidationResult(true, "", null, null);

	public boolean isValid() {
		return isValid;
	}

	public String getMessage() {
		return message;
	}

	public Object[] getErrorVals() {
		return errorVals;
	}

	String message;
	String translatedMessage;
	Object[] errorVals;

	public ValidationResult(boolean isValid, String message, Object[] errorVals, String translatedMessage) {
		this.isValid = isValid;
		this.message = message;
		this.errorVals = errorVals;
		this.translatedMessage = translatedMessage;
	}

	// factory methods
	public static ValidationResult of_(boolean isValid, String message, Object... errorVals) {
		return new ValidationResult(isValid, message, errorVals, null);
	}

	public static ValidationResult fail(String message, Object... errorVals) {
		return new ValidationResult(false, message, errorVals, null);
	}

	public static ValidationResult failWithTranslated(String message, Object... errorVals) {
		return new ValidationResult(false, null, errorVals, message);
	}

	public static ValidationResult failWithTranslated(String message) {
		return new ValidationResult(false, null, new Object[0], message);
	}
	
	public static ValidationResult ok() {
		// RFE: Could return always the same object! will reduce memory
		// footprint!
		return okResult;
	}

	public String getTranslatedMessage() {
		return translatedMessage;
	}

} @FunctionalInterface
public interface MessageSource {

	public String getMessage(String key);

	public default String getSafeMessage(String key) {
		try {
			String msg = this.getMessage(key);
			return msg;
		} catch (Exception e) {
			return "??" + key + "??";
		}
	}

	
	public default String getMessage(ValidationResult vr) {
		// give translated messages higher prio than message-keys
		if (vr.getTranslatedMessage() != null) {
			return vr.getTranslatedMessage();
		} else 
		if (vr.getMessage() != null) {
			return(String.format(this.getSafeMessage(
					vr.getMessage()
					), vr.getErrorVals()));
			
		} else {
			throw new IllegalArgumentException("ValidationResult has neither message-key nor translated text");
		}
	}

} @FunctionalInterface
public interface Request {
	public String getParameter(String name);
} public interface Validator {

	ValidationResult validate(FormCheckerElement elem);

}
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import com.coverity.security.Escape;
import de.jformchecker.AttributeUtils;
import de.jformchecker.Criterion;
import de.jformchecker.FormChecker;
import de.jformchecker.FormCheckerElement;
import de.jformchecker.StringUtils;
import de.jformchecker.TagAttributes;
import de.jformchecker.criteria.MaxLength;
import de.jformchecker.criteria.ValidationResult;
import de.jformchecker.message.MessageSource;
import de.jformchecker.request.Request;
import de.jformchecker.validator.Validator;
package de.jformchecker.elements;




/**
 * Parent Element for all Formchecker elements Common stuff like validation...
 * 
 * @author jochen
 *
 */
public abstract class AbstractInput <T extends FormCheckerElement> implements FormCheckerElement {

	protected String name;
	protected String value;
	protected String desc;
	protected String preSetValue = "";
	protected int size = -1;
	private List<Criterion> criteria = new ArrayList<>();
	boolean required;
	private int tabIndex;
	ValidationResult validationResult;