package fr.openwide.core.wicket.more.link.descriptor.parameter.mapping; import java.util.Collection; import org.apache.wicket.Component; import org.apache.wicket.injection.Injector; import org.apache.wicket.model.IComponentAssignedModel; import org.apache.wicket.model.IModel; import org.apache.wicket.model.IWrapModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.spring.injection.annot.SpringBean; import org.apache.wicket.util.lang.Args; import com.google.common.collect.ImmutableList; import fr.openwide.core.wicket.more.link.descriptor.builder.LinkDescriptorBuilder; import fr.openwide.core.wicket.more.link.descriptor.parameter.extractor.LinkParameterExtractionException; import fr.openwide.core.wicket.more.link.descriptor.parameter.extractor.LinkParameterExtractionRuntimeException; import fr.openwide.core.wicket.more.link.descriptor.parameter.injector.LinkParameterInjectionException; import fr.openwide.core.wicket.more.link.descriptor.parameter.injector.LinkParameterInjectionRuntimeException; import fr.openwide.core.wicket.more.link.service.ILinkParameterConversionService; /** * Implements a mapping between {@link IModel models} and their string representations as {@link PageParameters}. * <p>Consequently, the parameters values can change over time, especially between two Ajax refreshes. * <p>This is a read <em>and</em> write model, which means it allows setting the underlying models value by {@link #setObject(PageParameters) settings its own value}. * This feature, though, depends on two things: * <ul> * <li>the ability for the underlying models to support the {@link IModel#setObject(Object)} operation. * If they do not, the {@link LinkParametersMapping#setObject(PageParameters)} operation will crash.</li> * <li>the ability for the {@link ILinkParameterConversionService} to convert the application-side types of the parameters. * This should be checked upstream, for example in the {@link LinkDescriptorBuilder}. * </ul> */ public class LinkParametersMapping implements IModel<PageParameters>, IComponentAssignedModel<PageParameters> { private static final long serialVersionUID = -9066291686294702275L; private final Collection<ILinkParameterMappingEntry> parameterMappingEntries; @SpringBean private ILinkParameterConversionService conversionService; public LinkParametersMapping(Iterable<? extends ILinkParameterMappingEntry> parameterMappingEntries) { super(); Injector.get().inject(this); this.parameterMappingEntries = ImmutableList.copyOf(parameterMappingEntries); } @Override public PageParameters getObject() throws LinkParameterInjectionRuntimeException { PageParameters result = new PageParameters(); for (ILinkParameterMappingEntry parameterMappingEntry : parameterMappingEntries) { try { parameterMappingEntry.inject(result, conversionService); } catch (LinkParameterInjectionException e) { throw new LinkParameterInjectionRuntimeException(e); } } return result; } @Override public void setObject(PageParameters object) throws LinkParameterExtractionRuntimeException { Args.notNull(object, "object"); for (ILinkParameterMappingEntry parameterMappingEntry : parameterMappingEntries) { try { parameterMappingEntry.extract(object, conversionService); } catch (LinkParameterExtractionException e) { throw new LinkParameterExtractionRuntimeException(e); } } } @Override public WrapModel wrapOnAssignment(Component component) { return new WrapModel(component); } @Override public void detach() { for (ILinkParameterMappingEntry parameterMappingEntry : parameterMappingEntries) { parameterMappingEntry.detach(); } } private class WrapModel extends LinkParametersMapping implements IWrapModel<PageParameters> { private static final long serialVersionUID = -1776808095158473219L; public WrapModel(Component component) { super(wrapParameterModelMap(LinkParametersMapping.this.parameterMappingEntries, component)); } @Override public IModel<?> getWrappedModel() { return LinkParametersMapping.this; } } private static Collection<ILinkParameterMappingEntry> wrapParameterModelMap(Collection<ILinkParameterMappingEntry> parameterMappingEntries, Component component) { ImmutableList.Builder<ILinkParameterMappingEntry> builder = ImmutableList.builder(); for (ILinkParameterMappingEntry parameterMappingEntry : parameterMappingEntries) { builder.add(parameterMappingEntry.wrap(component)); } return builder.build(); } }