All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.elasticsearch.common.io.stream.NamedWriteableRegistry Maven / Gradle / Ivy

/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

package org.elasticsearch.common.io.stream;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * A registry for {@link org.elasticsearch.common.io.stream.Writeable.Reader} readers of {@link NamedWriteable}.
 *
 * The registration is keyed by the combination of the category class of {@link NamedWriteable}, and a name unique
 * to that category.
 */
public class NamedWriteableRegistry {

    /** An entry in the registry, made up of a category class and name, and a reader for that category class. */
    public static class Entry {

        /** The superclass of a {@link NamedWriteable} which will be read by {@link #reader}. */
        public final Class categoryClass;

        /** A name for the writeable which is unique to the {@link #categoryClass}. */
        public final String name;

        /** A reader capability of reading*/
        public final Writeable.Reader reader;

        /** Creates a new entry which can be stored by the registry. */
        public  Entry(Class categoryClass, String name, Writeable.Reader reader) {
            this.categoryClass = Objects.requireNonNull(categoryClass);
            this.name = Objects.requireNonNull(name);
            this.reader = Objects.requireNonNull(reader);
        }
    }

    /**
     * The underlying data of the registry maps from the category to an inner
     * map of name unique to that category, to the actual reader.
     */
    private final Map, Map>> registry;

    /**
     * Constructs a new registry from the given entries.
     */
    @SuppressWarnings("rawtypes")
    public NamedWriteableRegistry(List entries) {
        if (entries.isEmpty()) {
            registry = Map.of();
            return;
        }
        entries = new ArrayList<>(entries);
        entries.sort(Comparator.comparing(e -> e.categoryClass.getName()));

        Map, Map>> registry = new HashMap<>();
        Map> readers = null;
        Class currentCategory = null;
        for (Entry entry : entries) {
            if (currentCategory != entry.categoryClass) {
                if (currentCategory != null) {
                    // we've seen the last of this category, put it into the big map
                    registry.put(currentCategory, Map.copyOf(readers));
                }
                readers = new HashMap<>();
                currentCategory = entry.categoryClass;
            }

            Writeable.Reader oldReader = readers.put(entry.name, entry.reader);
            if (oldReader != null) {
                throw new IllegalArgumentException(
                    "NamedWriteable ["
                        + currentCategory.getName()
                        + "]["
                        + entry.name
                        + "]"
                        + " is already registered for ["
                        + oldReader.getClass().getName()
                        + "],"
                        + " cannot register ["
                        + entry.reader.getClass().getName()
                        + "]"
                );
            }
        }
        // handle the last category
        registry.put(currentCategory, Map.copyOf(readers));

        this.registry = Map.copyOf(registry);
    }

    /**
     * Returns a reader for a {@link NamedWriteable} object identified by the
     * name provided as argument and its category.
     */
    public  Writeable.Reader getReader(Class categoryClass, String name) {
        Map> readers = getReaders(categoryClass);
        return getReader(categoryClass, name, readers);
    }

    /**
     * @param categoryClass category of the reader
     * @param name          name of the writeable
     * @param readers       map of readers for the category
     * @return reader for the named writable of the given {@code name}
     */
    public static  Writeable.Reader getReader(
        Class categoryClass,
        String name,
        Map> readers
    ) {
        @SuppressWarnings("unchecked")
        Writeable.Reader reader = (Writeable.Reader) readers.get(name);
        if (reader == null) {
            throwOnUnknownWritable(categoryClass, name);
        }
        return reader;
    }

    /**
     * Gets the readers map keyed by name for the given category
     * @param categoryClass category to get readers map for
     * @return map of readers for the category
     */
    public  Map> getReaders(Class categoryClass) {
        Map> readers = registry.get(categoryClass);
        if (readers == null) {
            throwOnUnknownCategory(categoryClass);
        }
        return readers;
    }

    private static  void throwOnUnknownWritable(Class categoryClass, String name) {
        throw new IllegalArgumentException("Unknown NamedWriteable [" + categoryClass.getName() + "][" + name + "]");
    }

    private static  void throwOnUnknownCategory(Class categoryClass) {
        throw new IllegalArgumentException("Unknown NamedWriteable category [" + categoryClass.getName() + "]");
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy