<commit_before>/*
 * Copyright 2010-2010 LinkedIn, Inc
 *
 * 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.linkedin.groovy.util.state

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.concurrent.TimeoutException
import org.linkedin.util.clock.Clock
import org.linkedin.util.clock.SystemClock
import org.linkedin.util.annotations.Initializable
import org.linkedin.groovy.util.concurrent.GroovyConcurrentUtils
import org.linkedin.groovy.util.lang.GroovyLangUtils
import org.linkedin.util.lang.LangUtils

/**
 * Represents the state machine (states, transitions and action to take on each)
 *
 * Here is an example of a state machine transitions
 * <pre>
 *
 * def static DEFAULT_TRANSITIONS =
 * [
 *   NONE: [[to: 'installed', action: 'install']],
 *   installed: [[to: 'stopped', action: 'configure'], [to: NONE, action: 'uninstall']],
 *   stopped: [[to: 'running', action: 'start'], [to: 'stopped', action: 'configure'], [to: NONE, action: 'uninstall']],
 *   running: [[to: 'stopped', action: 'stop']]
 * ]
 * </pre>
 * @author <EMAIL>
 */
def class StateMachineImpl implements StateMachine
{
  public static final String MODULE = StateMachineImpl.class.getName();
  public static final Logger log = LoggerFactory.getLogger(MODULE);

  @Initializable
  Clock clock = SystemClock.INSTANCE

  private final Map<String, Collection<Map<String, String>>> _transitions
  private final Map<String, Integer> _depths
  private final def _shortestPathsCache = [:]
  private StateChangeListener _stateChangeListener
  private volatile def _currentState = NONE
  private volatile def _transitionAction = null
  private volatile def _transitionState = null
  private volatile def _error

  // the lock to use for synchronization
  def lock

  def StateMachineImpl(args)
  {
    if(!args.transitions)
      throw new IllegalArgumentException("missing transitions")

    _transitions = LangUtils.<Map<String, Collection<Map<String, String>>>>deepClone(args.transitions)
    _stateChangeListener = args.stateChangeListener
    _currentState = args.currentState ?: NONE
    _transitionAction = args.transitionAction
    _transitionState = args.transitionState
    _error = args.error
    _depths = [:]
    _transitions.keySet().each { state ->
      _depths[state] = computeDepth(state)
    }
    lock = args.lock ?: new Object()
  }

  private int computeDepth(state)
  {
    findPaths(NONE, state).min { c1, c2 ->
      return c1.size - c2.size
    }.size()
  }

  /**<commit_msg>#7: ArrayList.size has problem in groovy when using other JVMs than SUN's<commit_after>/*
 * Copyright 2010-2010 LinkedIn, Inc
 *
 * 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.linkedin.groovy.util.state

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import java.util.concurrent.TimeoutException
import org.linkedin.util.clock.Clock
import org.linkedin.util.clock.SystemClock
import org.linkedin.util.annotations.Initializable
import org.linkedin.groovy.util.concurrent.GroovyConcurrentUtils
import org.linkedin.groovy.util.lang.GroovyLangUtils
import org.linkedin.util.lang.LangUtils

/**
 * Represents the state machine (states, transitions and action to take on each)
 *
 * Here is an example of a state machine transitions
 * <pre>
 *
 * def static DEFAULT_TRANSITIONS =
 * [
 *   NONE: [[to: 'installed', action: 'install']],
 *   installed: [[to: 'stopped', action: 'configure'], [to: NONE, action: 'uninstall']],
 *   stopped: [[to: 'running', action: 'start'], [to: 'stopped', action: 'configure'], [to: NONE, action: 'uninstall']],
 *   running: [[to: 'stopped', action: 'stop']]
 * ]
 * </pre>
 * @author <EMAIL>
 */
def class StateMachineImpl implements StateMachine
{
  public static final String MODULE = StateMachineImpl.class.getName();
  public static final Logger log = LoggerFactory.getLogger(MODULE);

  @Initializable
  Clock clock = SystemClock.INSTANCE

  private final Map<String, Collection<Map<String, String>>> _transitions
  private final Map<String, Integer> _depths
  private final def _shortestPathsCache = [:]
  private StateChangeListener _stateChangeListener
  private volatile def _currentState = NONE
  private volatile def _transitionAction = null
  private volatile def _transitionState = null
  private volatile def _error

  // the lock to use for synchronization
  def lock

  def StateMachineImpl(args)
  {
    if(!args.transitions)
      throw new IllegalArgumentException("missing transitions")

    _transitions = LangUtils.<Map<String, Collection<Map<String, String>>>>deepClone(args.transitions)
    _stateChangeListener = args.stateChangeListener
    _currentState = args.currentState ?: NONE
    _transitionAction = args.transitionAction
    _transitionState = args.transitionState
    _error = args.error
    _depths = [:]
    _transitions.keySet().each { state ->
      _depths[state] = computeDepth(state)
    }
    lock = args.lock ?: new Object()
  }

  private int computeDepth(state)
  {
    findPaths(NONE, state).min { c1, c2 ->
      return c1.size() - c2.size()
    }.size()
  }

  /**
{'fraction_non_alphanumeric': 0.10384488991127178, 'fraction_numerical': 0.0060795267827801515, 'mean_word_length': 4.224892703862661, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4049828', 'n_tokens_mistral': 1777, 'n_tokens_neox': 1719, 'n_words': 553}