<commit_before>/*
 * Copyright 2007-2011 WorldWide Conferencing, LLC
 *
 * 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 net.liftweb
package actor

import java.util.concurrent._

/**
 * Rules for dealing with thread pools, both in lift-actor and
 * in lift-util
 */
object ThreadPoolRules {
  /**
   * When threads are created in the thread factories, should
   * they null the context class loader.  By default false,
   * but it you set it to true, Tomcat complains less about stuff.
   * Must be set in the first line of Boot.scala
   */
  @volatile var nullContextClassLoader: Boolean = false
}

/**
 * The LAPinger object schedules a LiftActor to be pinged "delay" miliseconds in the future.
 * The schedule method return a ScheduledFuture object which can be cancelled if necessary.
 */
object LAPinger {

  /**The underlying <code>java.util.concurrent.ScheduledExecutor</code> */
  private var service = Executors.newSingleThreadScheduledExecutor(TF)

  /**
   * Re-create the underlying <code>SingleThreadScheduledExecutor</code>
   */
  def restart: Unit = synchronized {
    if ((service eq null) || service.isShutdown)
      service = Executors.newSingleThreadScheduledExecutor(TF)
  }

  /**
   * Shut down the underlying <code>SingleThreadScheduledExecutor</code>
   */
  def shutdown: Unit = synchronized {
    service.shutdown
  }

  /**
   * Schedules the sending of a message to occur after the specified delay.
   *
   * @param to The LiftActor to send the message to.
   * @param msg The message to send.
   * @param delay The number of milliseconds to delay before sending msg
   * @return a <code>ScheduledFuture</code> which sends the <code>msg</code> to
   * the <code>to<code> Actor after the specified TimeSpan <code>delay</code>.
   */
  def schedule[T](to: SpecializedLiftActor[T], msg: T, delay: Long): ScheduledFuture[Unit] = {
    val r = new Callable[Unit] {
      def call: Unit = {
        to ! msg
      }
    }
    try {
      service.schedule(r, delay, TimeUnit.MILLISECONDS)
    } catch {
      case e: RejectedExecutionException => throw PingerException(msg + " could not be scheduled on " + to, e)
    }
  }

}

/**
 * Exception thrown if a ping can't be scheduled.
 */
case class PingerException(msg: String, e: Throwable) extends RuntimeException(msg, e)

private object TF extends ThreadFactory {
  val threadFactory = Executors.defaultThreadFactory()

  def newThread(r: Runnable): Thread = {
    val d: Thread = threadFactory.newThread(r)
    d setName "ActorPinger"
    d setDaemon true
    if (ThreadPoolRules.nullContextClassLoader) {
      d setContextClassLoader null
    }
    d
  }
}
<commit_msg>Further iteration on LAPinger doc<commit_after>/*
 * Copyright 2007-2011 WorldWide Conferencing, LLC
 *
 * 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 net.liftweb
package actor

import java.util.concurrent._

/**
 * Rules for dealing with thread pools, both in lift-actor and
 * in lift-util
 */
object ThreadPoolRules {
  /**
   * When threads are created in the thread factories, should
   * they null the context class loader.  By default false,
   * but it you set it to true, Tomcat complains less about stuff.
   * Must be set in the first line of Boot.scala
   */
  @volatile var nullContextClassLoader: Boolean = false
}

/**
 * LAPinger is for scheduling LiftActors to be pinged with an arbitrary message at some point
 * in the future.
 */
object LAPinger {

  /**The underlying <code>java.util.concurrent.ScheduledExecutor</code> */
  private var service = Executors.newSingleThreadScheduledExecutor(TF)

  /**
   * Re-create the underlying <code>SingleThreadScheduledExecutor</code>
   */
  def restart: Unit = synchronized {
    if ((service eq null) || service.isShutdown)
      service = Executors.newSingleThreadScheduledExecutor(TF)
  }

  /**
   * Shut down the underlying <code>SingleThreadScheduledExecutor</code>
   */
  def shutdown: Unit = synchronized {
    service.shutdown
  }

  /**
   * Schedules the sending of a message to occur after the specified delay.
   *
   * @param to The LiftActor to send the message to.
   * @param msg The message to send.
   * @param delay The number of milliseconds to delay before sending msg
   * @return a <code>ScheduledFuture</code> which sends the <code>msg</code> to
   * the <code>to<code> Actor after the specified TimeSpan <code>delay</code>.
   */
  def schedule[T](to: SpecializedLiftActor[T], msg: T, delay: Long): ScheduledFuture[Unit] = {
    val r = new Callable[Unit] {
      def call: Unit = {
        to ! msg
      }
    }
    try {
      service.schedule(r, delay, TimeUnit.MILLISECONDS)
    } catch {
      case e: RejectedExecutionException => throw PingerException(msg + " could not be scheduled on " + to, e)
    }
  }

}

/**
 * Exception thrown if a ping can't be scheduled.
 */
case class PingerException(msg: String, e: Throwable) extends RuntimeException(msg, e)

private object TF extends ThreadFactory {
  val threadFactory = Executors.defaultThreadFactory()

  def newThread(r: Runnable): Thread = {
    val d: Thread = threadFactory.newThread(r)
    d setName "ActorPinger"
    d setDaemon true
    if (ThreadPoolRules.nullContextClassLoader) {
      d setContextClassLoader null
    }
    d
  }
}
{'fraction_non_alphanumeric': 0.08872252309652756, 'fraction_numerical': 0.003822873526600828, 'mean_word_length': 3.4094101123595504, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 33, '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': '1084889', 'n_tokens_mistral': 1820, 'n_tokens_neox': 1750, 'n_words': 679}