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

org.algorithmx.rules.bind.ScopedBindings Maven / Gradle / Ivy

The newest version!
/**
 * This software is licensed under the Apache 2 license, quoted below.
 *
 * Copyright (c) 2019, algorithmx.org ([email protected])
 *
 * 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 org.algorithmx.rules.bind;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * Bindings with Scopes. Allows the user to create/remove scopes around the Bindings. Each Binding is tied to a
 * Scope and Binding is removed once the Scope is removed. Binding is treated much like a Local variable on a method stack.
 *
 * @author Max Arulananthan
 * @since 1.0
 */
public interface ScopedBindings extends Bindings {

    /**
     * Returns the current working scope.
     *
     * @return working scope.
     */
    Bindings getCurrentScope();

    /**
     * Returns all the available Scopes (in order which they were added).
     *
     * @return all available Scopes.
     */
    Iterable getScopes();

    /**
     * Returns all the available Scopes (in the opposite order which they were added).
     *
     * @return all available Scopes (in reverse order).
     */
    Iterable getScopesInReverseOrder();

    /**
     * Creates new scope and pushes it to the top of Stack.
     *
     * @return the newly created Bindings.
     */
    Bindings newScope();

    /**
     * Pops the working Bindings off the Stack.
     *
     * @return the removed Bindings.
     */
    Bindings endScope();

    /**
     * Retrieves the Binding identified by the given name. The search starts with working scope and goes back the Stack
     * until the initial scope. The search stops once a match is found.
     *
     * @param name name of the Binding.
     * @param  generic type of the Binding.
     * @return Binding if found; null otherwise.
     */
    @Override
    default  Binding getBinding(String name) {
        Binding result = null;

        for (Bindings scope : getScopes()) {
            result = scope.getBinding(name);
            if (result != null) break;
        }

        return result;
    }

    /**
     * Retrieves the Binding identified by the given name and type. The search starts with working scope and goes back the Stack
     * until the initial scope. The search stops once a match is found.
     *
     * @param name name of the Binding.
     * @param type type of the Binding.
     * @param  generic type of the Binding.
     * @return Binding if found; null otherwise.
     */
    @Override
    default  Binding getBinding(String name, TypeReference type) {
        Binding result = null;

        for (Bindings scope : getScopes()) {
            result = scope.getBinding(name, type);
            if (result != null) break;
        }

        return result;
    }

    /**
     * Retrieves all the Bindings of the given type. The search starts with working scope and goes back the Stack
     * until the initial scope. The search stops once a match is found.
     *
     * @param type desired type.
     * @param  generic type of the Binding.
     * @return all matching Bindings.
     */
    @Override
    default  Set> getBindings(TypeReference type) {
        Set> result = new HashSet<>();

        for (Bindings scope : getScopesInReverseOrder()) {
            result.addAll(scope.getBindings(type));
        }

        return result;
    }

    /**
     * Retrieves the Binding values as an Unmodifiable Map. The retrieval starts with working scope and goes back the Stack
     * until the initial scope.
     *
     * @return unmodifiable Map of the Binding values.
     */
    @Override
    default Map asMap() {
        Map result = new HashMap<>();

        for (Iterator> it = iterator(); it.hasNext();) {
            Binding binding = it.next();
            result.put(binding.getName(), binding.getValue());
        }

        return result;
    }

    /**
     * Retrieves the number of Bindings in all the scopes. All Bindings are accounted for (does not account for unique names).
     *
     * @return total number of Bindings (in all Scopes).
     */
    @Override
    default int size() {
        int result = 0;

        for (Bindings scope : getScopes()) {
            result += scope.size();
        }

        return result;
    }

    /**
     * Retrieves the number of unique (by name) Bindings in all the scopes.
     *
     * @return unique Bindings count.
     */
    default int uniqueSize() {
        return asMap().size();
    }

    /**
     * Iterator of all the Bindings starting withe working scope and going up the Stack.
     *
     * @return all bindings (reverse order).
     */
    default Iterator> iterator() {
        Set> result = new HashSet<>();

        for (Bindings scope : getScopesInReverseOrder()) {
            for (Iterator> it = scope.iterator(); it.hasNext();) {
                result.add(it.next());
            }
        }

        return result.iterator();
    }

    /**
     * Declares a new Binding given a name, type and an initial value in the current working scope.
     *
     * @param name name of the Binding.
     * @param type type reference of the Binding.
     * @param initialValue initial value of the Binding.
     * @param validationCheck validation to be performed when the value is changed.
     * @param mutable determines whether the value is mutable.
     * @param  generic type of the Binding.
     * @return this Bindings (fluent interface).
     * @throws org.algorithmx.rules.bind.BindingAlreadyExistsException thrown if the Binding already exists.
     * @throws org.algorithmx.rules.bind.InvalidBindingException thrown if we cannot set initial value.
     * @see Binding
     */
    @Override
    default  Bindings bind(String name, TypeReference type, T initialValue, Predicate validationCheck,
                              boolean mutable) throws BindingAlreadyExistsException, InvalidBindingException {
        return getCurrentScope().bind(name, type, initialValue, validationCheck, mutable);
    }

    /**
     * Binds the given Binding into the current scope. Follows the same rules as adding a new Binding with name, type, etc.
     *
     * @param binding existing Binding.
     * @param  generic type of the Binding.
     * @return this Bindings (fluent interface).
     * @throws org.algorithmx.rules.bind.BindingAlreadyExistsException thrown if the Binding already exists.
     */
    @Override
    default  Bindings bind(Binding binding) {
        return getCurrentScope().bind(binding);
    }

    /**
     * Binds all the given Bindings into current scope. Follows the same rules as adding a new Binding with name, type, etc.
     * The execution will stop if a Binding already exists.
     *
     *
     * @param bindings existing Bindings.
     * @param  generic type of the Binding.
     * @return this Bindings (fluent interface).
     * @throws org.algorithmx.rules.bind.BindingAlreadyExistsException thrown if a Binding already exists.
     */
    @Override
    default  Bindings bind(Collection> bindings) {
        return getCurrentScope().bind(bindings);
    }

    /**
     * Declares a new Binding given a name, type, the value retrieved using the supplied Supplier into the current scope.
     *
     * @param name name of the Binding.
     * @param valueSupplier the value of the Binding will be retrieved using this Supplier.
     * @param type type reference of the Binding.
     * @param  generic type of the Binding.
     * @return this Bindings (fluent interface).
     * @throws org.algorithmx.rules.bind.BindingAlreadyExistsException thrown if the Binding already exists.
     */
    @Override
    default  Bindings bind(String name, Supplier valueSupplier, TypeReference type) throws BindingAlreadyExistsException {
        return getCurrentScope().bind(name, valueSupplier, type);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy