001/**
002 * Copyright 2010-2014 The Kuali Foundation
003 *
004 * Licensed under the Educational Community License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/ecl2.php
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.kuali.common.util.base;
017
018import static com.google.common.base.Preconditions.checkState;
019import static java.util.concurrent.TimeUnit.MILLISECONDS;
020import static org.kuali.common.util.FormatUtils.getMillis;
021import static org.kuali.common.util.base.Exceptions.illegalState;
022
023import java.util.List;
024
025import com.google.common.base.Optional;
026import com.google.common.base.Stopwatch;
027
028public class Threads {
029
030    /**
031     * Check to make sure elapsed time on the stopwatch has not exceeded {@code timeout} and then sleep for the indicated number of milliseconds
032     *
033     * @throws IllegalStateException
034     *             if elapsed time on the stopwatch has exceeded {@code timeout} or if {@code InterruptedException} is thrown while sleeping
035     *
036     * @returns The number of milliseconds this method slept for
037     */
038    public static long checkedWait(Stopwatch sw, long timeout, long sleep) {
039        checkState(sw.elapsed(MILLISECONDS) <= timeout, "wait timeout exceeded");
040        return sleep(sleep);
041    }
042
043    /**
044     * Sleep for {@code time} where time is in the format 15ms, 15s, 15m, 15h, 15d, 15y for 15 milliseconds, seconds, minutes, hours, days, and years, respectively. Note that years
045     * is approximate as the logic always assumes exactly 365 days a year.
046     *
047     * @throws <code>IllegalStateException</code> if interrupted.
048     */
049    public static long sleep(String time) {
050        return sleep(getMillis(time));
051    }
052
053    /**
054     * Sleep for <code>millis</code> or zero, if {@code !millis.isPresent()}
055     *
056     * @throws <code>IllegalStateException</code> if interrupted.
057     */
058    public static long sleep(Optional<? extends Number> millis) {
059        if (millis.isPresent()) {
060            return sleep(millis.get().longValue());
061        } else {
062            return 0;
063        }
064    }
065
066    /**
067     * Sleep for <code>millis</code>
068     *
069     * @throws <code>IllegalStateException</code> if interrupted.
070     */
071    public static long sleep(long millis) {
072        try {
073            Thread.sleep(millis);
074            return millis;
075        } catch (InterruptedException e) {
076            throw illegalState(e);
077        }
078    }
079
080    /**
081     * Start each thread
082     */
083    public static void start(List<Thread> threads) {
084        for (Thread thread : threads) {
085            thread.start();
086        }
087    }
088
089    /**
090     * Invoke join() on each thread
091     *
092     * @throws <code>IllegalStateException</code> if any thread gets interrupted.
093     */
094    public static void join(List<Thread> threads) {
095        for (Thread thread : threads) {
096            try {
097                thread.join();
098            } catch (InterruptedException e) {
099                throw illegalState(e, "unexpected interruption [thread id:%s] [thread name:%s]", thread.getId(), thread.getName());
100            }
101        }
102    }
103}