001/* -*- mode: Java; c-basic-offset: 2; indent-tabs-mode: nil; coding: utf-8-unix -*-
002 *
003 * Copyright © 2020 microBean™.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
014 * implied.  See the License for the specific language governing
015 * permissions and limitations under the License.
016 */
017package org.microbean.settings.converter;
018
019import java.util.Collection;
020import java.util.Objects;
021
022import java.util.function.Function;
023
024import java.util.regex.Pattern;
025
026import javax.enterprise.inject.Vetoed;
027
028import org.microbean.settings.Converter;
029import org.microbean.settings.Value;
030
031@Vetoed
032public class CollectionConverter<C extends Collection<T>, T> implements Converter<C> {
033
034  private static final long serialVersionUID = 1L;
035
036  private static final Pattern backslashCommaPattern = Pattern.compile("\\\\,");
037
038  private static final Pattern splitPattern = Pattern.compile("(?<!\\\\),");
039
040  private final Function<? super Integer, ? extends C> collectionCreator;
041
042  private final Function<? super C, ? extends C> immutableCollectionCreator;
043
044  private final Converter<? extends T> scalarConverter;
045
046  public CollectionConverter(final Function<? super Integer, ? extends C> collectionCreator,
047                             final Function<? super C, ? extends C> immutableCollectionCreator,
048                             final Converter<? extends T> scalarConverter) {
049    super();
050    this.collectionCreator = Objects.requireNonNull(collectionCreator);
051    this.immutableCollectionCreator = immutableCollectionCreator;
052    this.scalarConverter = Objects.requireNonNull(scalarConverter);
053  }
054
055  @Override
056  public final C convert(final Value value) {
057    final C returnValue;
058    if (value == null) {
059      returnValue = null;
060    } else {
061      final C collection;
062      final String stringValue = value.get();
063      if (stringValue == null || stringValue.isEmpty()) {
064        collection = this.collectionCreator.apply(Integer.valueOf(0));
065      } else {
066        final String[] parts = split(stringValue);
067        assert parts != null;
068        assert parts.length > 0;
069        collection = this.collectionCreator.apply(Integer.valueOf(parts.length));
070        if (collection == null) {
071          throw new IllegalArgumentException("collectionCreator.apply(" + parts.length + ") == null");
072        }
073        for (final String part : parts) {
074          collection.add(this.scalarConverter.convert(new Value(value, part)));
075        }
076      }
077      assert collection != null;
078      if (this.immutableCollectionCreator != null) {
079        returnValue = this.immutableCollectionCreator.apply(collection);
080      } else {
081        returnValue = collection;
082      }
083    }
084    return returnValue;
085  }
086
087  private static final String[] split(final String text) {
088    final String[] returnValue;
089    if (text == null) {
090      returnValue = new String[0];
091    } else {
092      returnValue = splitPattern.split(text);
093      assert returnValue != null;
094      for (int i = 0; i < returnValue.length; i++) {
095        returnValue[i] = backslashCommaPattern.matcher(returnValue[i]).replaceAll(",");
096      }
097    }
098    return returnValue;
099  }
100
101
102}