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

com.rapiddweller.common.depend.Node Maven / Gradle / Ivy

Go to download

'rapiddweller Common' is an open source Java library forked from Databene Commons by Volker Bergmann. It provides extensions to the Java core library by utility classes, abstract concepts and concrete implementations.

There is a newer version: 2.0.1-jdk-11
Show newest version
/*
 * Copyright (C) 2004-2015 Volker Bergmann ([email protected]).
 * All rights reserved.
 *
 * 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.rapiddweller.common.depend;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.rapiddweller.common.depend.NodeState.FORCEABLE;
import static com.rapiddweller.common.depend.NodeState.FORCED;
import static com.rapiddweller.common.depend.NodeState.INACTIVE;
import static com.rapiddweller.common.depend.NodeState.INITIALIZABLE;
import static com.rapiddweller.common.depend.NodeState.INITIALIZED;
import static com.rapiddweller.common.depend.NodeState.PARTIALLY_INITIALIZABLE;
import static com.rapiddweller.common.depend.NodeState.PARTIALLY_INITIALIZED;

/**
 * Helper class for calculating dependencies.
 *
 * @param  the type parameter
 * @author Volker Bergmann
 * @since 0.3.04
 */
class Node> {

  private NodeState state;

  private final E subject;
  private final List> providers;
  private final List providerRequired;
  private final List> clients;

  /**
   * Instantiates a new Node.
   *
   * @param subject the subject
   */
  public Node(E subject) {
    super();
    this.subject = subject;
    this.providers = new ArrayList<>();
    this.providerRequired = new ArrayList<>();
    this.clients = new ArrayList<>();
    this.state = INITIALIZABLE; // As long as no providers are added, the node is initializable
  }

  // properties ------------------------------------------------------------------------------------------------------

  /**
   * Gets subject.
   *
   * @return the subject
   */
  public E getSubject() {
    return subject;
  }

  /**
   * Gets state.
   *
   * @return the state
   */
  public NodeState getState() {
    return state;
  }

  /**
   * Requires boolean.
   *
   * @param provider the provider
   * @return the boolean
   */
  public boolean requires(Node provider) {
    return providerRequired.get(providers.indexOf(provider));
  }

  /**
   * Gets providers.
   *
   * @return the providers
   */
  public List> getProviders() {
    return providers;
  }

  /**
   * Add provider node.
   *
   * @param provider the provider
   * @param required the required
   * @return the node
   */
  public Node addProvider(Node provider, boolean required) {
    if (!hasForeignProviders() && provider != this) // A provider is about to be added. If this was a standalone node so far,...
    {
      this.state = INACTIVE;                      // ...I need to reconsider
    }
    if (this.providers.contains(provider)) {
      if (required && !required(provider)) {
        providerRequired.set(providers.indexOf(provider), Boolean.TRUE);
        providersChanged();
      }
    } else {
      this.providers.add(provider);
      this.providerRequired.add(required);
      provider.addClient(this);
      providersChanged();
    }
    return this;
  }

  /**
   * Has foreign providers boolean.
   *
   * @return the boolean
   */
  public boolean hasForeignProviders() {
    if (providers.size() == 0) {
      return false;
    }
    for (Node provider : providers) {
      if (provider != this) {
        return true;
      }
    }
    return false;
  }

  /**
   * Required boolean.
   *
   * @param provider the provider
   * @return the boolean
   */
  public boolean required(Node provider) {
    return providerRequired.get(providers.indexOf(provider));
  }

  /**
   * Gets clients.
   *
   * @return the clients
   */
  public List> getClients() {
    return clients;
  }

  /**
   * Add client.
   *
   * @param client the client
   */
  public void addClient(Node client) {
    if (!this.clients.contains(client)) {
      this.clients.add(client);
    }
  }

  /**
   * Has foreign clients boolean.
   *
   * @return the boolean
   */
  public boolean hasForeignClients() {
    if (clients.size() == 0) {
      return false;
    }
    for (Node client : clients) {
      if (client != this) {
        return true;
      }
    }
    return false;
  }

  // interface -------------------------------------------------------------------------------------------------------

  /**
   * Providers changed.
   */
  void providersChanged() {
    if (state == INITIALIZABLE || state == INITIALIZED) {
      return;
    }
    // check initializability
    boolean initializable = true;
    boolean partiallyInitializable = true;
    for (Node provider : providers) {
      if (provider != this && !allowsClientInitialization(provider.getState())) {
        initializable = false;
        if (required(provider)) {
          partiallyInitializable = false;
        }
      }
    }
    if (initializable) {
      this.state = INITIALIZABLE;
      return;
    }
    if (state == PARTIALLY_INITIALIZED) {
      return;
    }
    if (partiallyInitializable) {
      this.state = PARTIALLY_INITIALIZABLE;
      return;
    }
    if (state != INACTIVE) {
      return;
    }
    if (!hasForeignProviders()) {
      this.state = FORCEABLE;
    }
    for (Node provider : providers) {
      if (provider != this && provider.getState() == INITIALIZED) {
        this.state = FORCEABLE;
        return;
      }
    }
  }

  private static boolean allowsClientInitialization(NodeState providerState) {
    return providerState == INITIALIZED || providerState == FORCED || providerState == PARTIALLY_INITIALIZED;
  }

  /**
   * Initialize.
   */
/*
      private boolean allProvidersInState(NodeState state) {
          for (Node provider : providers)
              if (provider.getState() != state)
                  return false;
          return true;
      }
  */
  public void initialize() {
    if (state != INITIALIZABLE) {
      throw new IllegalStateException("Node not initializable: " + this);
    }
    setState(INITIALIZED);
  }

  private void setState(NodeState state) {
    this.state = state;
    for (Node client : clients) {
      client.providersChanged();
    }
  }

  /**
   * Initialize partially.
   */
  public void initializePartially() {
    if (state != PARTIALLY_INITIALIZABLE) {
      throw new IllegalStateException("Node not partially initializable: " + this);
    }
    setState(PARTIALLY_INITIALIZED);
  }

  /**
   * Force.
   */
  public void force() {
    setState(FORCED);
  }

  /**
   * Assert state.
   *
   * @param state the state
   */
  void assertState(NodeState state) {
    if (this.state != state) {
      throw new IllegalStateException("Expected to be in state '" + state + "', "
          + "found: '" + this.state + "'");
    }
  }

  // java.lang.Object ------------------------------------------------------------------------------------------------

  @Override
  public int hashCode() {
    return subject.hashCode();
  }

  @SuppressWarnings("rawtypes")
  @Override
  public boolean equals(Object obj) {
    if (this == obj) {
      return true;
    }
    if (obj == null || getClass() != obj.getClass()) {
      return false;
    }
    final Node that = (Node) obj;
    return (Objects.equals(this.subject, that.subject));
  }

  @Override
  public String toString() {
    return subject.toString();
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy