package fr.openwide.core.wicket.more.link.descriptor.builder.impl.parameter.mapping; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import java.util.Collection; import org.apache.wicket.Component; import org.apache.wicket.model.IModel; import org.apache.wicket.request.mapper.parameter.PageParameters; import org.apache.wicket.util.lang.Args; import org.javatuples.Unit; import org.springframework.core.convert.TypeDescriptor; import com.google.common.base.Function; import com.google.common.base.Functions; import com.google.common.base.Supplier; import fr.openwide.core.commons.util.functional.SerializableFunction; import fr.openwide.core.wicket.more.link.descriptor.parameter.extractor.LinkParameterExtractionException; import fr.openwide.core.wicket.more.link.descriptor.parameter.injector.LinkParameterInjectionException; import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.AbstractLinkParameterMappingEntry; import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.ILinkParameterMappingEntry; import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.factory.AbstractLinkParameterMappingEntryFactory; import fr.openwide.core.wicket.more.link.descriptor.parameter.mapping.factory.ILinkParameterMappingEntryFactory; import fr.openwide.core.wicket.more.link.descriptor.parameter.validator.ILinkParameterValidator; import fr.openwide.core.wicket.more.link.descriptor.parameter.validator.SimpleMandatoryCollectionLinkParameterValidator; import fr.openwide.core.wicket.more.link.service.ILinkParameterConversionService; @SuppressWarnings("rawtypes") public class CollectionLinkParameterMappingEntry<C extends Collection> extends AbstractLinkParameterMappingEntry { private static final long serialVersionUID = 2126702467532153474L; public static <C extends Collection> ILinkParameterMappingEntryFactory<Unit<IModel<C>>> factory(final String parameterName, final Supplier<? extends TypeDescriptor> typeDescriptorSupplier, final Supplier<C> emptyCollectionSupplier) { Args.notNull(parameterName, "parameterName"); return new AbstractLinkParameterMappingEntryFactory<Unit<IModel<C>>>() { private static final long serialVersionUID = 1L; @Override public ILinkParameterMappingEntry create(Unit<IModel<C>> parameters) { return new CollectionLinkParameterMappingEntry<>( parameterName, parameters.getValue0(), typeDescriptorSupplier, emptyCollectionSupplier ); } }; } protected final String parameterName; protected final IModel<C> mappedModel; protected final Supplier<? extends TypeDescriptor> typeDescriptorSupplier; protected final Function<? super C, ? extends C> collectionCustomizerFunction; public CollectionLinkParameterMappingEntry(String parameterName, IModel<C> mappedModel, Supplier<? extends TypeDescriptor> typeDescriptorSupplier) { this(parameterName, mappedModel, typeDescriptorSupplier, Functions.<C>identity()); } /** * @param emptyCollectionSupplier Allows to perform fine-tuned customization on the actual collection instance that cannot be performed by * the conversionService itself (for example, instantiation of TreeSet with a specific comparator) */ public CollectionLinkParameterMappingEntry(String parameterName, IModel<C> mappedModel, Supplier<? extends TypeDescriptor> typeDescriptorSupplier, final Supplier<? extends C> emptyCollectionSupplier) { this(parameterName, mappedModel, typeDescriptorSupplier, emptyCollectionSupplier == null ? Functions.<C>identity() : new SerializableFunction<C, C>() { private static final long serialVersionUID = 1L; @Override @SuppressWarnings("unchecked") public C apply(C input) { C newCollection = emptyCollectionSupplier.get(); newCollection.addAll(input); return newCollection; } }); } public CollectionLinkParameterMappingEntry(String parameterName, IModel<C> mappedModel, Supplier<? extends TypeDescriptor> typeDescriptorSupplier, Function<? super C, ? extends C> collectionCustomizerFunction) { checkNotNull(parameterName); checkNotNull(mappedModel); checkNotNull(typeDescriptorSupplier); checkNotNull(typeDescriptorSupplier.get()); checkNotNull(collectionCustomizerFunction); checkArgument( typeDescriptorSupplier.get().isCollection(), "typeDescriptorSupplier must be a collection type" ); checkNotNull( typeDescriptorSupplier.get().getElementTypeDescriptor(), "typeDescriptorSupplier's element type must be defined" ); this.parameterName = parameterName; this.mappedModel = mappedModel; this.typeDescriptorSupplier = typeDescriptorSupplier; this.collectionCustomizerFunction = collectionCustomizerFunction; } @Override public void inject(PageParameters targetParameters, ILinkParameterConversionService conversionService) throws LinkParameterInjectionException { C collection = mappedModel.getObject(); if (collection != null && collection.isEmpty()) { collection = null; // Just make sure that the default spring converter for collections won't translate this to an empty string. } inject(targetParameters, conversionService, parameterName, collection); } @Override public void extract(PageParameters sourceParameters, ILinkParameterConversionService conversionService) throws LinkParameterExtractionException { TypeDescriptor typeDescriptor = typeDescriptorSupplier.get(); Object extractedCollection = extract(sourceParameters, conversionService, parameterName, typeDescriptor); @SuppressWarnings("unchecked") C castedCollection = (C)typeDescriptor.getType().cast(extractedCollection); C finalCollection = collectionCustomizerFunction.apply(castedCollection); mappedModel.setObject(finalCollection); } @Override public ILinkParameterMappingEntry wrap(Component component) { IModel<C> wrappedModel = wrap(mappedModel, component); return new CollectionLinkParameterMappingEntry<>(parameterName, wrappedModel, typeDescriptorSupplier, collectionCustomizerFunction); } @Override public ILinkParameterValidator mandatoryValidator() { return new SimpleMandatoryCollectionLinkParameterValidator(parameterName, mappedModel); } @Override public void detach() { mappedModel.detach(); } }