package org.nocket.gen.page.visitor.bind.builder.components;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.IFormSubmitter;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.IRequestParameters;
import org.nocket.component.form.BeanValidationForm;
import org.nocket.component.form.behaviors.ValidationTooltipStyleBehavior;
import org.nocket.component.form.behaviors.ValidationTooltipStyleGroupBehavior;
import org.nocket.gen.domain.ValidationErrorPresentation;
import org.nocket.gen.page.DMDWebGenPageContext;
import org.nocket.gen.page.element.FeedbackElement;
import org.nocket.gen.page.element.PageElementI;
import org.nocket.gen.page.element.synchronizer.EagerAjaxFormSubmitBehavior;
public class GeneratedBeanValidationForm<T> extends BeanValidationForm<T> {
private static final Logger log = Logger.getLogger(GeneratedBeanValidationForm.class);
private static final long serialVersionUID = 1L;
/**
* If an input field, that is connected with an model attribute, that is
* annotated with an eager annotation, will send a ajax request to the server.
* While processing this request it is necessary that the setter of the
* model attribute is called after all other setters are called. The reason
* is, that all data has to synchronized to their models, because the setter
* could use the synchronized values.<br>
* In Wicket it seemed to be impossible to change the order of setter calls
* except the iterator of a form.<br>
* It's not a good idea to copy the original wicket iterator, so it was
* necessary to put something between the wicket iterator and the consumer
* of the iterator.<br>
* This FormEagerComponentDelayingIterator checks the request to look for
* the attribute, that is responsible for the ajax call. Than the
* FormEagerComponentDelayingIterator encapsulates the wicket iterator and
* holds back the desired setter call. This setter call will be processed
* last.
*/
private final class FormEagerComponentDelayingIterator implements Iterator<Component> {
private final Iterator<Component> realIterator;
private String holdBackComponentName = null;
private Component holdBackComponent = null;
private FormEagerComponentDelayingIterator(Iterator<Component> realIterator) {
this.realIterator = realIterator;
this.holdBackComponentName = extractSubmittingComponentIdFromRequest();
}
public boolean hasNext() {
return holdBackComponent != null || realIterator.hasNext();
}
public Component next() {
if (!realIterator.hasNext()) {
if (holdBackComponent == null) {
throw new NoSuchElementException();
}
Component result = holdBackComponent;
holdBackComponent = null;
return result;
}
Component next = realIterator.next();
if (next.getId().equals(holdBackComponentName)) {
holdBackComponent = next;
return realIterator.hasNext() ? realIterator.next() : holdBackComponent;
}
return next;
}
public void remove() {
realIterator.remove();
}
}
private String submittingComponentId;
private boolean eagerProcessing;
private boolean forcedProcessing;
private DMDWebGenPageContext context;
public GeneratedBeanValidationForm(DMDWebGenPageContext context, String id, IModel<T> model) {
super(id, model);
this.context = context;
setValidationErrorPresentation();
}
protected void setValidationErrorPresentation() {
if (context.getConfiguration().getValidationErrorPresentation() == ValidationErrorPresentation.TOOLTIP) {
setValidationStyleBehaviorClass(ValidationTooltipStyleBehavior.class);
setValidationStyleGroupBehaviorClass(ValidationTooltipStyleGroupBehavior.class);
}
}
@Override
protected String getComponentPropertyPath(FormComponent component) {
if (context.getComponentRegistry().getComponent(FeedbackElement.DEFAULT_WICKET_ID) != null) {
return null;
} else {
PageElementI<?> element = context.getPageRegistry().getElement(component.getId());
if (element == null) {
return null;
} else if (element.isDomainElement()) {
return element.getBeanValidationExpression();
} else {
return null;
}
}
}
@Override
protected String getValidatorPropertyPath(FormComponent c) {
PageElementI<?> element = context.getPageRegistry().getElement(c.getId());
if (element == null) {
return null;
} else if (element.isDomainElement()) {
return element.getBeanValidationPropertyName();
} else {
return null;
}
}
@Override
protected String getValidatorPropertyPrompt(FormComponent c) {
PageElementI<?> element = context.getPageRegistry().getElement(c.getId());
if (element == null) {
return c.getId();
} else if (element.isDomainElement()) {
return element.getDomainElement().getPrompt();
} else {
return c.getId();
}
}
public Iterator<Component> iterator() {
final Iterator<Component> realIterator = super.iterator();
return new FormEagerComponentDelayingIterator(realIterator);
}
public void process(IFormSubmitter submittingComponent) {
this.submittingComponentId = extractSubmittingComponentIdFromRequest();
this.eagerProcessing = isEagerSubmit();
this.forcedProcessing = isForcedSubmit();
log.debug("Processing request: submittingComponentId=" + submittingComponentId + ", isEagerProcessing=" + eagerProcessing + ", isForcedProcessing=" + forcedProcessing);
super.process(submittingComponent);
}
public boolean isForcedProcessing() {
return forcedProcessing;
}
public boolean isEagerProcessing() {
return eagerProcessing;
}
public String getSubmittingComponentId() {
return submittingComponentId;
}
private boolean isEagerSubmit() {
return getPostParameterAsBoolean(EagerAjaxFormSubmitBehavior.NOCKET_EAGER);
}
private boolean isForcedSubmit() {
return getPostParameterAsBoolean(EagerAjaxFormSubmitBehavior.NOCKET_FORCED);
}
private boolean getPostParameterAsBoolean(String name) {
IRequestParameters postParameters = getRequest().getPostParameters();
return postParameters == null ? false : postParameters.getParameterValue(name).toBoolean();
}
protected String extractSubmittingComponentIdFromRequest() {
String res = null;
Set<String> parameterNames = getRequest().getQueryParameters().getParameterNames();
if (parameterNames != null) {
for (String string : parameterNames) {
// a useless paramter that is added by
if (!"random".equalsIgnoreCase(string)) {
res = StringUtils.substringAfterLast(string, "-");
break;
}
}
}
return res;
}
}