/*
* Copyright © 2015 Cask Data, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package co.cask.cdap.api.dataset.lib;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.Nonnull;
/**
* Types and methods to specify partitioning keys for datasets.
*/
public class PartitionKey {
private final Map<String, Comparable> fields;
/**
* Private constructor to force use of the builder.
*/
private PartitionKey(@Nonnull Map<String, Comparable> fields) {
this.fields = Collections.unmodifiableMap(new LinkedHashMap<>(fields));
}
/**
* @return all field names and their values in a map.
*/
public Map<String, Comparable> getFields() {
return fields;
}
/**
* @return the value of a field
*/
public Comparable getField(String fieldName) {
return fields.get(fieldName);
}
@Override
public String toString() {
return fields.toString();
}
@Override
public boolean equals(Object other) {
return this == other ||
(other != null && getClass() == other.getClass()
&& getFields().equals(((PartitionKey) other).getFields())); // fields is never null
}
@Override
public int hashCode() {
return fields.hashCode(); // fields is never null
}
/**
* @return a builder for a partitioning
*/
public static Builder builder() {
return new Builder();
}
/**
* A builder for partitioning objects.
*/
public static class Builder {
private final LinkedHashMap<String, Comparable> fields = new LinkedHashMap<>();
private Builder() { }
/**
* Add a field with a given name and value.
*
* @param name the field name
* @param value the value of the field
*
* @throws java.lang.IllegalArgumentException if the field name is null, empty, or already exists,
* or if the value is null.
*/
public Builder addField(String name, Comparable value) {
if (name == null || name.isEmpty()) {
throw new IllegalArgumentException("Field name cannot be null or empty.");
}
if (value == null) {
throw new IllegalArgumentException("Field value cannot be null.");
}
if (fields.containsKey(name)) {
throw new IllegalArgumentException(String.format("Field '%s' already exists in partition key.", name));
}
fields.put(name, value);
return this;
}
/**
* Add field of type STRING.
*
* @param name the field name
* @param value the value of the field
*
* @throws java.lang.IllegalArgumentException if the field name is null, empty, or already exists,
* or if the value is null.
*/
public Builder addStringField(String name, String value) {
return addField(name, value);
}
/**
* Add field of type INT.
*
* @param name the field name
* @param value the value of the field
*
* @throws java.lang.IllegalArgumentException if the field name is null, empty, or already exists,
* or if the value is null.
*/
public Builder addIntField(String name, int value) {
return addField(name, value);
}
/**
* Add field of type LONG.
*
* @param name the field name
* @param value the value of the field
*
* @throws java.lang.IllegalArgumentException if the field name is null, empty, or already exists,
* or if the value is null.
*/
public Builder addLongField(String name, long value) {
return addField(name, value);
}
/**
* Create the partition key.
*
* @throws java.lang.IllegalStateException if no fields have been added
*/
public PartitionKey build() {
if (fields.isEmpty()) {
throw new IllegalStateException("Partition key cannot be empty.");
}
return new PartitionKey(fields);
}
}
}