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

org.apache.solr.common.ConfigNode Maven / Gradle / Ivy

There is a newer version: 9.7.0
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.solr.common;

import static org.apache.solr.common.ConfigNode.Helpers._bool;
import static org.apache.solr.common.ConfigNode.Helpers._double;
import static org.apache.solr.common.ConfigNode.Helpers._int;
import static org.apache.solr.common.ConfigNode.Helpers._txt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * A generic interface that represents a config file, mostly XML Please note that this is an
 * immutable, read-only object.
 */
public interface ConfigNode {
  ThreadLocal> SUBSTITUTES = new ThreadLocal<>();

  /** Name of the tag */
  String name();

  /** Attributes */
  Map attributes();

  /** Child by name */
  default ConfigNode child(String name) {
    return child(null, name);
  }

  /**
   * Child by name or return an empty node if null. If there are multiple values, it returns the
   * first element. This never returns a null.
   */
  default ConfigNode get(String name) {
    ConfigNode child = child(null, name);
    return child == null ? EMPTY : child;
  }

  default ConfigNode get(String name, Predicate test) {
    List children = getAll(test, name);
    if (children.isEmpty()) return EMPTY;
    return children.get(0);
  }

  default ConfigNode get(String name, int idx) {
    List children = getAll(null, name);
    if (idx < children.size()) return children.get(idx);
    return EMPTY;
  }

  default ConfigNode child(String name, Supplier err) {
    ConfigNode n = child(name);
    if (n == null) throw err.get();
    return n;
  }

  default boolean boolVal(boolean def) {
    return _bool(txt(), def);
  }

  default int intVal(int def) {
    return _int(txt(), def);
  }

  default String attr(String name, String def) {
    return _txt(attributes().get(name), def);
  }

  default String attr(String name) {
    return attributes().get(name);
  }

  default String requiredStrAttr(String name, Supplier err) {
    String attr = attr(name);
    if (attr == null && err != null) throw err.get();
    return attr;
  }

  default int intAttr(String name, int def) {
    return _int(attr(name), def);
  }

  default boolean boolAttr(String name, boolean def) {
    return _bool(attr(name), def);
  }

  default String txt(String def) {
    return txt() == null ? def : txt();
  }

  String txt();

  default double doubleVal(double def) {
    return _double(txt(), def);
  }

  /** Iterate through child nodes with the name and return the first child that matches */
  default ConfigNode child(Predicate test, String name) {
    ConfigNode[] result = new ConfigNode[1];
    forEachChild(
        it -> {
          if (name != null && !name.equals(it.name())) return Boolean.TRUE;
          if (test == null || test.test(it)) {
            result[0] = it;
            return Boolean.FALSE;
          }
          return Boolean.TRUE;
        });
    return result[0];
  }

  /**
   * Iterate through child nodes with the names and return all the matching children
   *
   * @param nodeNames names of tags to be returned
   * @param test check for the nodes to be returned
   */
  default List getAll(Predicate test, String... nodeNames) {
    return getAll(
        test, nodeNames == null ? Collections.emptySet() : new HashSet<>(Arrays.asList(nodeNames)));
  }

  /**
   * Iterate through child nodes with the names and return all the matching children
   *
   * @param matchNames names of tags to be returned
   * @param test check for the nodes to be returned
   */
  default List getAll(Predicate test, Set matchNames) {
    List result = new ArrayList<>();
    forEachChild(
        it -> {
          if (matchNames != null && !matchNames.isEmpty() && !matchNames.contains(it.name()))
            return Boolean.TRUE;
          if (test == null || test.test(it)) result.add(it);
          return Boolean.TRUE;
        });
    return result;
  }

  default List getAll(String name) {
    return getAll(null, Collections.singleton(name));
  }

  default boolean exists() {
    return true;
  }

  default boolean isNull() {
    return false;
  }

  /**
   * abortable iterate through children
   *
   * @param fun consume the node and return true to continue or false to abort
   */
  void forEachChild(Function fun);

  /** An empty node object. usually returned when the node is absent */
  ConfigNode EMPTY =
      new ConfigNode() {
        @Override
        public String name() {
          return null;
        }

        @Override
        public String txt() {
          return null;
        }

        @Override
        public Map attributes() {
          return Map.of();
        }

        @Override
        public String attr(String name) {
          return null;
        }

        @Override
        public String attr(String name, String def) {
          return def;
        }

        @Override
        public ConfigNode child(String name) {
          return null;
        }

        @Override
        public ConfigNode get(String name) {
          return EMPTY;
        }

        @Override
        public boolean exists() {
          return false;
        }

        @Override
        public boolean isNull() {
          return true;
        }

        @Override
        public void forEachChild(Function fun) {}
      };

  class Helpers {
    static boolean _bool(Object v, boolean def) {
      return v == null ? def : Boolean.parseBoolean(v.toString());
    }

    static String _txt(Object v, String def) {
      return v == null ? def : v.toString();
    }

    static int _int(Object v, int def) {
      return v == null ? def : Integer.parseInt(v.toString());
    }

    static double _double(Object v, double def) {
      return v == null ? def : Double.parseDouble(v.toString());
    }

    public static Predicate at(int i) {
      return new Predicate<>() {
        int index = 0;

        @Override
        public boolean test(ConfigNode node) {
          if (index == i) return true;
          index++;
          return false;
        }
      };
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy