/* * Copyright 2010, Maarten Billemont * * 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.lyndir.omicron.api; import static com.google.common.base.Preconditions.checkArgument; import static com.lyndir.omicron.api.error.ExceptionUtils.*; import com.google.common.base.Preconditions; import com.lyndir.lhunath.opal.system.util.Job; import com.lyndir.lhunath.opal.system.util.ObjectUtils; import com.lyndir.omicron.api.error.*; import java.util.*; import javax.annotation.Nonnull; /** * @author lhunath, 2013-08-10 */ public final class Security { private static final ThreadLocal<Game> activeGameTL = new ThreadLocal<>(); private static final ThreadLocal<Player> activePlayerTL = new ThreadLocal<>(); private static final ThreadLocal<Deque<Player>> activePlayerJobTL = new ThreadLocal<Deque<Player>>() { @Override protected Deque<Player> initialValue() { return new LinkedList<>(); } }; private static final ThreadLocal<Deque<Boolean>> godJobTL = new ThreadLocal<Deque<Boolean>>() { @Override protected Deque<Boolean> initialValue() { return new LinkedList<>(); } }; static <R> R godRun(final Job<R> job) { if (isGod()) // Already god. return job.execute(); try { // Become god. godJobTL.get().push( true ); return job.execute(); } finally { // Become mortal. Preconditions.checkState( godJobTL.get().pop(), "Expected to be god." ); } } static void godRun(final Runnable job) { if (isGod()) { // Already god. job.run(); return; } try { // Become god. godJobTL.get().push( true ); job.run(); } finally { // Become mortal. Preconditions.checkState( godJobTL.get().pop(), "Expected to be god." ); } } @SuppressWarnings("ObjectEquality") static void playerRun(final Player jobPlayer, final Runnable job) { try { godJobTL.get().push( false ); activePlayerJobTL.get().push( jobPlayer ); job.run(); } finally { Preconditions.checkState( !godJobTL.get().pop(), "Expected to not be god." ); Preconditions.checkState( activePlayerJobTL.get().pop() == jobPlayer, "Expected to pop player for job." ); } } public static void activateGame(final Game game) { activeGameTL.set( game ); } public static void activatePlayer(final Player player) { activePlayerTL.set( player ); } public static void activatePlayerRun(final Player currentPlayer, final Runnable job) { checkArgument( currentPlayer.isCurrentPlayer(), "Cannot authenticate, player is not the current player: ", currentPlayer ); playerRun( currentPlayer, job ); } static boolean isAuthenticated() { return activePlayerTL.get() != null; } static boolean isGod() { return !godJobTL.get().isEmpty() && godJobTL.get().peek(); } /** * @return true if the current player is god or can observe the target. * * @see Player#canObserve(GameObservable) */ static boolean currentPlayerCanObserve(final GameObservable gameObservable) { return isGod() || currentPlayer().canObserve( gameObservable ).isTrue(); } @Nonnull static Player currentPlayer() throws NotAuthenticatedException { Player jobPlayer = activePlayerJobTL.get().peek(); if (jobPlayer != null) return jobPlayer; Player currentPlayer = activePlayerTL.get(); ExceptionUtils.assertSecure( currentPlayer != null, NotAuthenticatedException.class ); assert currentPlayer != null; return currentPlayer; } @Nonnull static Game currentGame() throws NotAuthenticatedException { Game currentGame = activeGameTL.get(); ExceptionUtils.assertSecure( currentGame != null, NotAuthenticatedException.class ); assert currentGame != null; return currentGame; } public static void assertOwned(final GameObservable observable) throws NotAuthenticatedException, NotOwnedException { if (isGod()) return; Optional<? extends IPlayer> owner = observable.getOwner(); assertSecure( owner.isPresent() && ObjectUtils.equals( owner.get(), currentPlayer() ), // NotOwnedException.class, observable ); } public static void assertObservable(final GameObservable observable) throws NotAuthenticatedException, NotObservableException { if (isGod()) return; assertSecure( currentPlayer().canObserve( observable ).isTrue(), // NotObservableException.class, observable ); } }