/* * Copyright (C) 2011-2014 Chris Vest (mr.chrisvest@gmail.com) * * 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 stormpot; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; public class ExpireKit { public interface Expire { boolean hasExpired(SlotInfo<? extends Poolable> info) throws Exception; } public interface SlotInfoCapture { void capture(SlotInfo<? extends Poolable> info); } public interface CountingExpiration extends Expiration<GenericPoolable> { int countExpirations(); } static class ExpireSeq { private final Expire[] checks; private int counter; ExpireSeq(Expire... checks) { this.checks = checks; counter = 0; } boolean checkNext( SlotInfo<? extends GenericPoolable> info) throws Exception { Expire expire = checks[counter]; counter = Math.min(checks.length - 1, counter + 1); return expire.hasExpired(info); } } private static class CountingExpirationImpl implements CountingExpiration { private final ExpireSeq expires; private final AtomicInteger counts; private CountingExpirationImpl(Expire... checks) { expires = new ExpireSeq(checks); counts = new AtomicInteger(); } @Override public int countExpirations() { return counts.get(); } @Override public boolean hasExpired( SlotInfo<? extends GenericPoolable> info) throws Exception { counts.incrementAndGet(); return expires.checkNext(info); } } public static CountingExpiration expire(Expire... checks) { return new CountingExpirationImpl(checks); } public static final Expire $fresh = info -> false; public static final Expire $expired = info -> true; public static final Expire $explicitExpire = info -> { GenericPoolable poolable = (GenericPoolable) info.getPoolable(); poolable.expire(); return false; }; public static Expire $if( final AtomicBoolean cond, final Expire then, final Expire otherwise) { return info -> cond.get()? then.hasExpired(info) : otherwise.hasExpired(info); } public static Expire $expiredIf(final AtomicBoolean cond) { return $if(cond, $expired, $fresh); } public static Expire $throwExpire(final Exception exception) { return info -> { throw exception; }; } public static Expire $throwExpire(final Throwable throwable) { return info -> { UnitKit.sneakyThrow(throwable); return false; }; } public static Expire $countDown( final CountDownLatch latch, final Expire then) { return info -> { latch.countDown(); return then.hasExpired(info); }; } public static Expire $capture( final SlotInfoCapture capture, final Expire then) { return info -> { capture.capture(info); return then.hasExpired(info); }; } public static SlotInfoCapture $age(final AtomicLong age) { return info -> age.set(info.getAgeMillis()); } public static SlotInfoCapture $poolable( final AtomicReference<Poolable> ref) { return info -> ref.set(info.getPoolable()); } public static SlotInfoCapture $claimCount(final AtomicLong count) { return info -> count.set(info.getClaimCount()); } public static SlotInfoCapture $slotInfo( final AtomicReference<SlotInfo<? extends Poolable>> ref) { return ref::set; } }