/*
* 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 com.facebook.presto.decoder;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.collect.SetMultimap;
import io.airlift.log.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import static com.facebook.presto.decoder.FieldDecoder.DEFAULT_FIELD_DECODER_NAME;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.base.Preconditions.checkState;
import static java.lang.String.format;
import static java.util.Objects.requireNonNull;
/**
* Manages Row and Field decoders for the various dataFormat values.
*/
public class DecoderRegistry
{
private static final Logger log = Logger.get(DecoderRegistry.class);
private final Map<String, RowDecoder> rowDecoders;
private final Map<String, SetMultimap<Class<?>, FieldDecoder<?>>> fieldDecoders;
@Inject
DecoderRegistry(Set<RowDecoder> rowDecoders, Set<FieldDecoder<?>> fieldDecoders)
{
requireNonNull(rowDecoders, "rowDecoders is null");
ImmutableMap.Builder<String, RowDecoder> rowBuilder = ImmutableMap.builder();
for (RowDecoder rowDecoder : rowDecoders) {
rowBuilder.put(rowDecoder.getName(), rowDecoder);
}
this.rowDecoders = rowBuilder.build();
Map<String, ImmutableSetMultimap.Builder<Class<?>, FieldDecoder<?>>> fieldDecoderBuilders = new HashMap<>();
for (FieldDecoder<?> fieldDecoder : fieldDecoders) {
ImmutableSetMultimap.Builder<Class<?>, FieldDecoder<?>> fieldDecoderBuilder = fieldDecoderBuilders.get(fieldDecoder.getRowDecoderName());
if (fieldDecoderBuilder == null) {
fieldDecoderBuilder = ImmutableSetMultimap.builder();
fieldDecoderBuilders.put(fieldDecoder.getRowDecoderName(), fieldDecoderBuilder);
}
for (Class<?> clazz : fieldDecoder.getJavaTypes()) {
fieldDecoderBuilder.put(clazz, fieldDecoder);
}
}
ImmutableMap.Builder<String, SetMultimap<Class<?>, FieldDecoder<?>>> fieldDecoderBuilder = ImmutableMap.builder();
for (Map.Entry<String, ImmutableSetMultimap.Builder<Class<?>, FieldDecoder<?>>> entry : fieldDecoderBuilders.entrySet()) {
fieldDecoderBuilder.put(entry.getKey(), entry.getValue().build());
}
this.fieldDecoders = fieldDecoderBuilder.build();
log.debug("Field decoders found: %s", this.fieldDecoders);
}
/**
* Return the specific row decoder for a given data format.
*/
public RowDecoder getRowDecoder(String dataFormat)
{
checkState(rowDecoders.containsKey(dataFormat), "no row decoder for '%s' found", dataFormat);
return rowDecoders.get(dataFormat);
}
/**
* Return the best matching field decoder for a given row data format, field type and a possible field data format name. If no
* name was given or an unknown field data type was given, fall back to the default decoder.
*/
public FieldDecoder<?> getFieldDecoder(String rowDataFormat, Class<?> fieldType, @Nullable String fieldDataFormat)
{
requireNonNull(rowDataFormat, "rowDataFormat is null");
requireNonNull(fieldType, "fieldType is null");
checkState(fieldDecoders.containsKey(rowDataFormat), "no field decoders for '%s' found", rowDataFormat);
Set<FieldDecoder<?>> decoders = fieldDecoders.get(rowDataFormat).get(fieldType);
ImmutableSet<String> fieldNames = ImmutableSet.of(
firstNonNull(fieldDataFormat, DEFAULT_FIELD_DECODER_NAME),
DEFAULT_FIELD_DECODER_NAME);
for (String fieldName : fieldNames) {
for (FieldDecoder<?> decoder : decoders) {
if (fieldName.equals(decoder.getFieldDecoderName())) {
return decoder;
}
}
}
throw new IllegalStateException(format("No field decoder for %s/%s found!", rowDataFormat, fieldType));
}
}