/* * 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 com.sun.jini.thread; import java.rmi.NoSuchObjectException; import java.rmi.RemoteException; /** * Utility class used to prevent access to a service before it has completed * its initialization or after it starts to shutdown. Each public entry point * to the service should call <code>check</code> or <code>shutdown</code>, * and initialization should call <code>ready</code> when the service is ready * to use. * * @author Sun Microsystems, Inc. * @since 2.1 */ public class ReadyState { // flag to indicate the service is initializing private static final int INITIALIZE = 0; // flag to indicate the service is ready to use private static final int READY = 1; // flag to indicate the service is shutting down private static final int SHUTDOWN = 2; private int state = INITIALIZE; /** * Checks if the service is ready to use, waiting if it is * initializing, and throwing <code>NoSuchObjectException</code> if it is * shutting down. Note that the <code>NoSuchObjectException</code> will be * wrapped in a <code>RemoteExceptionWrapper</code>. */ public synchronized void check() { while (true) { switch (state) { case INITIALIZE: try { wait(); } catch (InterruptedException e) {} break; case READY: return; default: throw new RemoteExceptionWrapper(new NoSuchObjectException( "service is unavailable")); } } } /** * Marks the service ready for use. This method should only be called * from the code that performs the service initialization, and it should * only be called once. */ public synchronized void ready() { switch (state) { case INITIALIZE: state = READY; notifyAll(); break; default: throw new AssertionError("ready is only called when the" + " service is in the INITIALIZE" + " state"); } } /** * Marks the service as shutting down, waiting if it is initializing, * and throwing <code>NoSuchObjectException</code> if it is already * shutting down. Note that the <code>NoSuchObjectException</code> will be * wrapped in a <code>RemoteExceptionWrapper</code>. */ public synchronized void shutdown() { check(); state = SHUTDOWN; notifyAll(); } /** * Wrapper used to prevent a <code>RemoteException</code> from being * wrapped in a <code>ServerException</code> by the RMI implementation. */ private static class RemoteExceptionWrapper extends RuntimeException { /** added for consistency; this will never be used */ private static final long serialVersionUID = 1L; /** the exception that will be written to the output stream */ private final RemoteException wrapped; /** Simple constructor */ public RemoteExceptionWrapper(RemoteException wrapped) { this.wrapped = wrapped; } /** returns the exception to marshal */ private Object writeReplace() { return wrapped; } } }