001package com.identityworksllc.iiq.common;
002
003import java.util.*;
004
005/**
006 * A builder for MapTuple objects. These are objects that function as
007 * tuples, allowing access by either index or by key. To use this class,
008 * construct a new instance at the top of your operation, such as:
009 *
010 * MapTupleBuilder mtb = new MapTupleBuilder("identity", "accountName", "date");
011 *
012 * Then, for each item, such as from a ResultSet, do this:
013 *
014 * MapTuple tuple = mtb.of(resultSet.getString("identity"), resultSet.getString("name"), resultSet.getDate("created"));
015 *
016 * In this example, the value for 'identity' can be accessed any of these ways:
017 *
018 * tuple.get("identity");
019 * tuple.getAt(0);
020 * tuple.getFirst();
021 *
022 */
023public class MapTupleBuilder {
024
025    /**
026     * Gets the list of keys
027     */
028    private final List<String> keys;
029
030    /**
031     * Constructs a new MapTupleBuilder, with the given list of keys.
032     * This constructor is private. One of the withKeys() methods should
033     * be used.
034     *
035     * Keys cannot be null and cannot be duplicated.
036     *
037     * @param keysList The list of keys
038     */
039    private MapTupleBuilder(List<String> keysList) {
040        for(String k : Objects.requireNonNull(keysList)) {
041            Objects.requireNonNull(k, "Key in keys list cannot be null");
042        }
043
044        Set<String> duplicatesRemoved = new HashSet<>(keysList);
045        if (duplicatesRemoved.size() != keysList.size()) {
046            throw new IllegalArgumentException("Duplicate keys are not allowed in MapTuple");
047        }
048
049        this.keys = Collections.unmodifiableList(keysList);
050    }
051
052    /**
053     * Constructs a new MapTupleBuilder with the keys in the list.
054     * @param keys At least one key to use in the resulting tuples
055     * @return A builder with the given keys
056     */
057    public static MapTupleBuilder withKeys(String... keys) {
058        if (keys.length == 0) {
059            throw new IllegalArgumentException("You must specify at least one key");
060        }
061        List<String> keysList = new ArrayList<>(Arrays.asList(keys));
062        return new MapTupleBuilder(keysList);
063    }
064
065    /**
066     * Constructs a new MapTupleBuilder with the keys in the list.
067     * @param keys A list containing at least one non-null key to use the resulting tuples
068     * @return A builder with the given keys
069     */
070    public static MapTupleBuilder withKeys(List<String> keys) {
071        if (keys == null || keys.isEmpty()) {
072            throw new IllegalArgumentException("You must specify at least one key");
073        }
074        return new MapTupleBuilder(keys);
075    }
076
077    /**
078     * Constructs a {@link MapTuple} pairing this builder's keys with the given
079     * values, both in order. The number of values must match the number of keys.
080     *
081     * @param values The values to add
082     * @return The resulting map
083     */
084    public MapTuple of(Object... values) {
085        return ofList(Arrays.asList(values));
086    }
087
088    /**
089     * Constructs a {@link MapTuple} pairing this builder's keys with the given
090     * values, both in order. The number of values must match the number of keys.
091     *
092     * @param values The values to add
093     * @return The resulting map
094     */
095    public MapTuple ofList(List<Object> values) {
096        if (values.size() != keys.size()) {
097            throw new IllegalArgumentException("MapTuple argument mismatch: got " + values.size() + " values, expected " + keys.size());
098        }
099        MapTuple result = new MapTuple(this.keys);
100        for(int i = 0; i < values.size(); i++) {
101            result.put(keys.get(i), values.get(i));
102        }
103        return result;
104    }
105
106}