/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.jini.export; import com.sun.jini.resource.Service; import java.rmi.server.ServerNotActiveException; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import net.jini.io.context.ClientHost; import net.jini.io.context.ClientSubject; import net.jini.security.Security; /** * The <code>ServerContext</code> class contains static methods to * execute some action within an appropriate server context for the * current thread and to obtain the server context for the current thread. * * <p>For example, an {@link Exporter} implementation may supply context * information for incoming calls dispatched to its exported remote objects * via the {@link #doWithServerContext ServerContext.doWithServerContext} * method. * * @author Sun Microsystems, Inc. * * @since 2.0 * @see net.jini.io.context.ClientHost * @see net.jini.io.context.ClientSubject **/ public final class ServerContext { private static final ThreadLocal state = new ThreadLocal(); private static final ServerContext.Spi[] providers = (ServerContext.Spi[]) Security.doPrivileged(new PrivilegedAction() { public Object run() { ClassLoader cl = ClassLoader.getSystemClassLoader(); ArrayList list = new ArrayList(1); Iterator i = Service.providers(ServerContext.Spi.class, cl); while (i.hasNext()) { list.add(i.next()); } return list.toArray(new ServerContext.Spi[list.size()]); } }); /** * Prevents instantiation. */ private ServerContext() { } /** * Sets the server context for the current thread to the supplied * <code>context</code> collection and invokes the <code>run</code> method * of the supplied <code>runnable</code> object. When this method * returns, the thread's server context is unset. * * <p>If a server context is currently set for the current thread, * that server context cannot be reset; that is, a server context * cannot be overwritten or nested. If a server context is already * set for the current thread, an <code>IllegalStateException</code> is * thrown. * * @param runnable the action to perform in the server context * @param context the context to set * * @throws NullPointerException if <code>context</code> or * <code>runnable</code> is <code>null</code> * @throws IllegalStateException if the context is already * set for this thread * @see #getServerContextElement **/ public static void doWithServerContext(Runnable runnable, Collection context) { if (context == null) { throw new NullPointerException("context cannot be null"); } if (state.get() != null) { throw new IllegalStateException( "context is already set for this thread"); } state.set(context); try { runnable.run(); } finally { state.set(null); } } /** * Returns the server context collection for the current thread. If no * server context collection has been explicitly specified via a * previous call to {@link #doWithServerContext * ServerContext.doWithServerContext}, then an ordered list of * providers (obtained as specified below) implementing the {@link * ServerContext.Spi} interface is consulted. {@link * ServerContext.Spi#getServerContext} is called on each provider in * turn; the first non-<code>null</code> return value is returned by * this method. If no provider is able to supply a server context * collection, then a <code>ServerNotActiveException</code> is thrown. * * <p>The list of server context providers is obtained as follows. For * each resource named * <code>META-INF/services/net.jini.export.ServerContext$Spi</code> * that is visible to the system class loader, the contents of the * resource are parsed as UTF-8 text to produce a list of class names. * The resource must contain a list of fully-qualified class names, one per * line. Space and tab characters surrounding each name, as well as blank * lines, are ignored. The comment character is <tt>'#'</tt>; all * characters on each line starting with the first comment character are * ignored. Each class name (that is not a duplicate of any previous class * name) is loaded through the system class loader, and the resulting * class must be assignable to {@link ServerContext.Spi} and have a public * no-argument constructor. The constructor is invoked to create a fallback * context provider instance. An implementation is permitted to search for * provider instances eagerly (i.e., upon startup), and cache the * verifier instances rather than recreating them on every call. * * <p>The contents of the collection are determined by the caller of * {@link #doWithServerContext ServerContext.doWithServerContext}. The * context information available from a given element of the collection * is determined by that element's type. Examples of types that a * given element might implement include {@link ClientHost} and {@link * ClientSubject}. * * <p>The order of the elements in the collection is insignificant. * The collection may be empty. * * <p>The caller of this method cannot assume that the returned * collection is modifiable. * * @return the server context for the current thread * @throws ServerNotActiveException if no context is set for the * current thread **/ public static Collection getServerContext() throws ServerNotActiveException { Collection context = (Collection) state.get(); if (context == null) { for (int i = 0; i < providers.length; i++) { if ((context = providers[i].getServerContext()) != null) { break; } } } if (context == null) { throw new ServerNotActiveException("not in remote call"); } return context; } /** * Defines the interface for server context providers, which are * consulted by {@link ServerContext#getServerContext} if no server context * has been explicitly associated with the current thread via a previous * call to {@link ServerContext#doWithServerContext}. */ public interface Spi { /** * Returns a server context collection for the current thread, or * <code>null</code> if provider does not contain context for the * current thread. * * <p>The context information available from a given element of * the collection is determined by that element's type. The order * of the elements is insignificant. The collection may be empty. * * <p>The caller of this method cannot assume that the returned * collection is modifiable. * * @return the server context for the current thread, * or <code>null</code> if none known */ Collection getServerContext(); } /** * Returns the first element in the current server context collection * (obtained by calling {@link #getServerContext * ServerContext.getServerContext}) that is an instance of the given * type <code>type</code>. If no element in the collection is an * instance of the type <code>type</code>, then <code>null</code> is * returned. * * @param type the type of the element * @return the first element in the server context collection that is * an instance of the type <code>type</code> or <code>null</code> * @throws ServerNotActiveException if no server context is set for * the current thread **/ public static Object getServerContextElement(Class type) throws ServerNotActiveException { Collection context = getServerContext(); Iterator iter = context.iterator(); while (iter.hasNext()) { Object elem = iter.next(); if (elem != null && type.isAssignableFrom(elem.getClass())) { return elem; } } return null; } }