/* * Copyright 2007-2010 Sun Microsystems, Inc. * * This file is part of Project Darkstar Server. * * Project Darkstar Server is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation and * distributed hereunder to you. * * Project Darkstar Server is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * -- */ package com.sun.sgs.impl.kernel; import com.sun.sgs.app.ChannelManager; import com.sun.sgs.app.DataManager; import com.sun.sgs.app.ManagerNotFoundException; import com.sun.sgs.app.TaskManager; import com.sun.sgs.app.TransactionNotActiveException; import com.sun.sgs.app.TransactionTimeoutException; import com.sun.sgs.auth.Identity; import com.sun.sgs.service.Transaction; /** * This class is used to resolve the state associated with the current task's * context, including its owner and active transaction. */ final class ContextResolver { // the context of any current thread, needed only so that we can run // multiple stacks in the same VM private static ThreadLocal<KernelContext> context = new ThreadLocal<KernelContext>(); // the current owner of any given thread private static ThreadLocal<Identity> currentOwner = new ThreadLocal<Identity>(); // the current transaction for any given thread private static ThreadLocal<Transaction> currentTransaction = new ThreadLocal<Transaction>(); /** * Private constructor used to ensure that no one constructs an instance * of this class. */ private ContextResolver() { } /** * Returns the {@code ChannelManager} used in this context. * * @return the context's {@code ChannelManager}. * * @throws IllegalStateException if there is no available * {@code ChannelManager} in this * context */ public static ChannelManager getChannelManager() { return context.get().getChannelManager(); } /** * Returns the {@code DataManager} used in this context. * * @return the context's {@code DataManager}. * * @throws IllegalStateException if there is no available * {@code DataManager} in this * context */ public static DataManager getDataManager() { return context.get().getDataManager(); } /** * Returns the {@code TaskManager} used in this context. * * @return the context's {@code TaskManager}. * * @throws IllegalStateException if there is no available * {@code TaskManager} in this * context */ public static TaskManager getTaskManager() { return context.get().getTaskManager(); } /** * Returns the manager in this context that matches the given type. * * @param <T> the type of the manager * @param type the {@code Class} of the requested manager * * @return the matching manager * * @throws ManagerNotFoundException if no manager is found that matches * the given type * @throws IllegalStateException if there are no available managers * in this context */ public static <T> T getManager(Class<T> type) { return context.get().getManager(type); } /** * Package-private method used to set task state. This is called each * time a task is run through a {@code Scheduler} * * @param ctx the {@code KernelContext} for the current task * @param owner the {@code Identity} that owns the current task */ static void setTaskState(KernelContext ctx, Identity owner) { context.set(ctx); currentOwner.set(owner); } /** * Package-private method used to get the current context. * * @return the current {@code AppKernelAppContext} */ static KernelContext getContext() { return context.get(); } /** * Returns the current owner of the work being done by this thread. * * @return the {@code Identity} that owns the current task */ static Identity getCurrentOwner() { return currentOwner.get(); } /** * Returns the current <code>Transaction</code>, throwing an exception * if there is no currently active transaction or if the currently * active transaction has timed out. * * @return the currently active <code>Transaction</code> * * @throws TransactionNotActiveException if there is no currently active * transaction * @throws TransactionTimeoutException if the transaction has timed out */ static Transaction getCurrentTransaction() { Transaction txn = currentTransaction.get(); if (txn == null) { throw new TransactionNotActiveException("no current transaction"); } if (txn.isAborted()) { throw new TransactionNotActiveException("Transaction is aborted", txn.getAbortCause()); } txn.checkTimeout(); return txn; } /** * Returns {@code true} if there is a current transaction, no matter * the state of that transaction. * * @return {@code true} if there is a current transaction */ static boolean inTransaction() { Transaction txn = currentTransaction.get(); return (txn != null); } /** * Sets the current <code>Transaction</code>, throwing an exception if * there is already an active transaction. * * @param transaction the <code>Transaction</code> to set as currently * active * * @throws IllegalStateException if there is already an active transaction */ static void setCurrentTransaction(Transaction transaction) { if (transaction == null) { throw new NullPointerException("null transactions not allowed"); } Transaction txn = currentTransaction.get(); if (txn != null) { throw new IllegalStateException("an active transaction is " + "currently running"); } currentTransaction.set(transaction); } /** * Clears the currently active <code>Transaction</code>. This is * typically done once a transaction has finished. * * @param transaction the <code>Transaction</code> to clear, which * must be the currently active transaction * * @throws IllegalStateException if there is no currently active * transaction to clear * @throws IllegalArgumentException if the given <code>Transaction</code> * is not the active transaction */ static void clearCurrentTransaction(Transaction transaction) { if (transaction == null) { throw new NullPointerException("transaction cannot be null"); } Transaction txn = currentTransaction.get(); if (txn == null) { throw new IllegalStateException("no active transaction to clear"); } if (!txn.equals(transaction)) { throw new IllegalArgumentException("provided transaction is " + "not currently active"); } currentTransaction.set(null); } /** * Returns whether there is a currently active transaction. * * @return <code>true</code> if there is currently an active transaction, * <code>false</code> otherwise */ static boolean isCurrentTransaction() { return (currentTransaction.get() != null); } }