| /* |
| * 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 org.apache.yoko.orb.OB; |
| |
| import static org.apache.yoko.orb.OB.MinorCodes.MinorDestroyWouldBlock; |
| import static org.apache.yoko.orb.OB.MinorCodes.MinorORBDestroyed; |
| import static org.apache.yoko.orb.OB.MinorCodes.MinorShutdownCalled; |
| import static org.apache.yoko.orb.OB.MinorCodes.describeBadInvOrder; |
| import static org.apache.yoko.orb.OB.MinorCodes.describeInitialize; |
| import static org.omg.CORBA.CompletionStatus.COMPLETED_NO; |
| |
| import java.util.concurrent.CountDownLatch; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Phaser; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.TimeoutException; |
| import java.util.concurrent.locks.ReadWriteLock; |
| |
| import org.apache.yoko.orb.OBPortableServer.POAManagerFactory_impl; |
| import org.apache.yoko.orb.OBPortableServer.POA_impl; |
| import org.apache.yoko.orb.PortableServer.Current_impl; |
| import org.omg.CORBA.BAD_INV_ORDER; |
| import org.omg.CORBA.INITIALIZE; |
| import org.omg.CORBA.ORBPackage.InvalidName; |
| import org.omg.PortableServer.POA; |
| import org.omg.PortableServer.CurrentPackage.NoContext; |
| |
| public final class ORBControl { |
| // |
| // The ORB instance |
| // |
| ORBInstance orbInstance_; |
| |
| // |
| // The ORBControl state |
| // |
| private enum State { NOT_RUNNING, RUNNING, SERVER_SHUTDOWN, CLIENT_SHUTDOWN, DESTROYED }; |
| private volatile State state; // State of the ORB |
| |
| // |
| // Has shutdown been called? |
| // |
| private final CountDownLatch shutdown = new CountDownLatch(1); |
| |
| // |
| // The Root POA |
| // |
| private POA rootPOA_; // The Root POA |
| |
| // |
| // The thread id of the main thread (that is the first thread that |
| // calls run, perform_work or work_pending) |
| // |
| private volatile Thread mainThread_; |
| |
| private long shutdownTimeout_ = 2;//seconds |
| |
| |
| // ---------------------------------------------------------------------- |
| // ORBControl private and protected member implementations |
| // ---------------------------------------------------------------------- |
| |
| // |
| // Complete shutdown of the ORB, if necessary |
| // |
| private synchronized void completeServerShutdown() { |
| // |
| // If the shutdown_ is false, or the server side has already |
| // shutdown then do nothing |
| // |
| if (shutdown.getCount() != 0 || state == State.SERVER_SHUTDOWN) |
| return; |
| |
| Assert._OB_assert(state != State.CLIENT_SHUTDOWN && state != State.DESTROYED); |
| |
| // |
| // If run was called then only the main thread may complete the |
| // shutdown |
| // |
| Assert._OB_assert(state == State.NOT_RUNNING || mainThread_ == Thread.currentThread()); |
| |
| // |
| // Get the POAManagerFactory implementation |
| // |
| POAManagerFactory_impl factory = (POAManagerFactory_impl) orbInstance_.getPOAManagerFactory(); |
| |
| // |
| // Deactivate all of the POAManagers |
| // |
| factory._OB_deactivate(); |
| |
| // |
| // Wait for all the threads in the server worker group to |
| // terminate |
| // |
| waitForServerThreads(); |
| notifyAll(); |
| } |
| |
| private void waitForServerThreads() { |
| shutdownExecutor(orbInstance_.getServerPhaser(), orbInstance_.getServerExecutor()); |
| |
| // |
| // Get the DispatchStrategyFactory implementation and |
| // destroy it. It must be destroyed here so that the |
| // thread pools get destroyed before OCI::Current_impl |
| // gets destroyed by the destruction of the Root |
| // POA. Otherwise, thread specific data for the thread |
| // pool threads will not get released. |
| // |
| DispatchStrategyFactory dsFactory = orbInstance_.getDispatchStrategyFactory(); |
| |
| DispatchStrategyFactory_impl dsFactoryImpl = (DispatchStrategyFactory_impl) dsFactory; |
| |
| dsFactoryImpl._OB_destroy(); |
| |
| // |
| // Mark the server side state as shutdown and notify any |
| // waiting threads |
| // |
| state = State.SERVER_SHUTDOWN; |
| |
| // |
| // Destroy the root POA |
| // |
| if (rootPOA_ != null) { |
| rootPOA_.destroy(true, true); |
| rootPOA_ = null; |
| } |
| } |
| |
| // |
| // Validate the state |
| // |
| private synchronized void validateState() { |
| // |
| // The ORB destroys this object, so it's an initialization |
| // error if the this operation is called after ORB destruction |
| // |
| if (state == State.DESTROYED) |
| throw new org.omg.CORBA.INITIALIZE( |
| org.apache.yoko.orb.OB.MinorCodes.describeInitialize(org.apache.yoko.orb.OB.MinorCodes.MinorORBDestroyed), |
| org.apache.yoko.orb.OB.MinorCodes.MinorORBDestroyed, org.omg.CORBA.CompletionStatus.COMPLETED_NO); |
| |
| if (state == State.SERVER_SHUTDOWN || state == State.CLIENT_SHUTDOWN) |
| throw new org.omg.CORBA.BAD_INV_ORDER( |
| org.apache.yoko.orb.OB.MinorCodes.describeBadInvOrder(org.apache.yoko.orb.OB.MinorCodes.MinorShutdownCalled), |
| org.apache.yoko.orb.OB.MinorCodes.MinorShutdownCalled, org.omg.CORBA.CompletionStatus.COMPLETED_NO); |
| |
| if (state == State.NOT_RUNNING) { |
| // |
| // Remember the main thread id |
| // |
| mainThread_ = Thread.currentThread(); |
| |
| // |
| // Set the state to State.RUNNING |
| // |
| state = State.RUNNING; |
| } |
| } |
| |
| private synchronized void blockServerShutdownComplete() { |
| // |
| // Wait for the server side to shutdown. Note that the client |
| // side shutting down or the state being destroyed also |
| // implies that the server side has shutdown |
| // |
| while (state == State.RUNNING) { |
| try { |
| wait(); |
| } catch (InterruptedException ex) { |
| } |
| } |
| } |
| |
| // ---------------------------------------------------------------------- |
| // ORBControl public member implementations |
| // ---------------------------------------------------------------------- |
| |
| public ORBControl() { |
| state = State.NOT_RUNNING; |
| } |
| |
| // |
| // Destroy the ORBControl |
| // |
| public synchronized void destroy() { |
| // |
| // destroy() may not be called unless the client side has been |
| // shutdown |
| // |
| Assert._OB_assert(state == State.CLIENT_SHUTDOWN); |
| state = State.DESTROYED; |
| |
| // |
| // Set the ORBInstance object to nil |
| // |
| orbInstance_ = null; |
| } |
| |
| // |
| // Set the ORBInstance object |
| // |
| public void setORBInstance(ORBInstance instance) { |
| orbInstance_ = instance; |
| } |
| |
| // |
| // Determine if there if the ORB needs the main thread to perform |
| // some work |
| // |
| public boolean workPending() { |
| validateState(); |
| |
| // |
| // If this is not the main thread then do nothing |
| // |
| if (mainThread_ != Thread.currentThread()) |
| return false; |
| |
| // |
| // Validate state will throw an exception if state is |
| // ServerShutdown, ClientShutdown or Destroyed. Therefore if |
| // shutdown_ is true, then a server side shutdown is pending. |
| // |
| return (shutdown.getCount() == 0); |
| } |
| |
| // |
| // Perform one unit of work |
| // |
| public void performWork() { |
| validateState(); |
| |
| // |
| // If this is not the main thread then do nothing |
| // |
| if (mainThread_ != Thread.currentThread()) |
| return; |
| |
| completeServerShutdown(); |
| } |
| |
| // |
| // Run the ORB event loop |
| // |
| public void run() { |
| validateState(); |
| |
| // |
| // If this is not the main thread then block until the ORB is |
| // shutdown |
| // |
| if (mainThread_ != Thread.currentThread()) { |
| blockServerShutdownComplete(); |
| return; |
| } |
| |
| // |
| // Validate state will throw an exception if state is |
| // ServerShutdown, ClientShutdown or Destroyed. Therefore if |
| // shutdown_ is true, then a server side shutdown is pending |
| // so complete it now. |
| // |
| if (shutdown.getCount() == 0) { |
| completeServerShutdown(); |
| return; |
| } |
| |
| // |
| // Block until the ORB server side has shutdown. Note that the |
| // client side shutting down or the state being destroyed also |
| // implies that the server side has shutdown |
| // |
| do { |
| try { |
| shutdown.await(); |
| } catch (InterruptedException ignored) { |
| } |
| |
| // |
| // After this call state is either ShutdownClient, or |
| // Running |
| // |
| completeServerShutdown(); |
| } while (state == State.RUNNING); |
| } |
| |
| // |
| // Shutdown the server side of the ORB |
| // |
| // ASYNC SAFE if waitForCompletion == false |
| // |
| public void shutdownServer(boolean waitForCompletion) { |
| // |
| // The ORB destroys this object, so it's an initialization error |
| // if the this operation is called after ORB destruction |
| // |
| if (state == State.DESTROYED) |
| throw new INITIALIZE(describeInitialize(MinorORBDestroyed), MinorORBDestroyed, COMPLETED_NO); |
| |
| if (state == State.SERVER_SHUTDOWN || state == State.CLIENT_SHUTDOWN) |
| throw new BAD_INV_ORDER(describeBadInvOrder(MinorShutdownCalled), MinorShutdownCalled, COMPLETED_NO); |
| |
| // |
| // If waitForCompletion is true then find out whether we're inside |
| // a method invocation -- if so throw a BAD_INV_ORDER exception |
| // |
| if (waitForCompletion) { |
| boolean inInvocation = false; |
| try { |
| InitialServiceManager initialServiceManager = orbInstance_.getInitialServiceManager(); |
| org.omg.CORBA.Object o = initialServiceManager.resolveInitialReferences("POACurrent"); |
| Current_impl current = (Current_impl) o; |
| inInvocation = current._OB_inUpcall(); |
| if (inInvocation) { |
| // |
| // Check whether or not the request is dispatched in this |
| // POAManager's ORB or another ORB. |
| // |
| try { |
| POA_impl p = (POA_impl) current.get_POA(); |
| inInvocation = (p._OB_ORBInstance() == orbInstance_); |
| } catch (NoContext ex) { |
| } |
| } |
| } catch (ClassCastException ex) { |
| } catch (InvalidName ex) { |
| } |
| |
| if (inInvocation) |
| throw new BAD_INV_ORDER(describeBadInvOrder(MinorDestroyWouldBlock), MinorDestroyWouldBlock, COMPLETED_NO); |
| } |
| |
| // |
| // Unblock run(). This should be done immediately before |
| // the return since this can cause the main loop to wake and |
| // complete the shutdown (thus, for instance, destroying the |
| // POAManagerFactory). |
| // |
| shutdown.countDown(); |
| |
| // |
| // waitForCompletion false? We're done. |
| // |
| if (!waitForCompletion) |
| return; |
| |
| // |
| // If run was called and this is not the main thread and |
| // waitForCompletion is true then wait for the shutdown to |
| // complete. |
| // |
| if (state == State.RUNNING && mainThread_ != Thread.currentThread()) { |
| blockServerShutdownComplete(); |
| return; |
| } |
| |
| // |
| // This is the main thread -- complete the shutdown process |
| // |
| completeServerShutdown(); |
| } |
| |
| // |
| // Shutdown the server (if necessary) & client side of the ORB |
| // |
| public synchronized void shutdownServerClient() { |
| // |
| // The ORB destroys this object, so it's an initialization |
| // error if the this operation is called after ORB destruction |
| // |
| if (state == State.DESTROYED) |
| throw new org.omg.CORBA.INITIALIZE( |
| org.apache.yoko.orb.OB.MinorCodes.describeInitialize(org.apache.yoko.orb.OB.MinorCodes.MinorORBDestroyed), |
| org.apache.yoko.orb.OB.MinorCodes.MinorORBDestroyed, org.omg.CORBA.CompletionStatus.COMPLETED_NO); |
| |
| // |
| // If the ORB client side is already shutdown, then we're done |
| // |
| if (state == State.CLIENT_SHUTDOWN) |
| return; |
| |
| if (orbInstance_ != null) { |
| // |
| // First shutdown the server side, if necessary |
| // |
| if (state != State.SERVER_SHUTDOWN) |
| shutdownServer(true); |
| |
| // |
| // The server shutdown must have completed |
| // |
| Assert._OB_assert(state == State.SERVER_SHUTDOWN); |
| |
| // |
| // Shutdown the client side. Continue to dispatch events until all |
| // client type event handlers have unregistered. |
| // |
| ClientManager clientManager = orbInstance_.getClientManager(); |
| clientManager.destroy(); |
| |
| // |
| // Wait for all the threads in the client worker group to |
| // terminate |
| // |
| shutdownExecutor(orbInstance_.getClientPhaser(), orbInstance_.getClientExecutor()); |
| } |
| |
| // |
| // Mark the ORB's client side as shutdown and notify any |
| // waiters |
| // |
| state = State.CLIENT_SHUTDOWN; |
| notifyAll(); |
| } |
| |
| private void shutdownExecutor(Phaser phaser, ExecutorService executor) { |
| int phase = phaser.arrive();//release the system's "lock" |
| //phaser advances after all GIOPConnectionThreaded have shut down (gracefully or abort) |
| try { |
| phaser.awaitAdvanceInterruptibly(phase, shutdownTimeout_, TimeUnit.SECONDS); |
| } catch (InterruptedException e1) { |
| Thread.currentThread().interrupt(); |
| } catch (TimeoutException e) { |
| } finally { |
| phaser.forceTermination(); |
| } |
| executor.shutdownNow(); |
| } |
| |
| // |
| // Initialize the Root POA |
| // |
| public void initializeRootPOA(org.omg.CORBA.ORB orb) { |
| String serverId = orbInstance_.getServerId(); |
| |
| // |
| // If there is no server id then set to "_RootPOA" |
| // |
| if (serverId.length() == 0) |
| serverId = "_RootPOA"; |
| |
| // |
| // Get the initial service manager |
| // |
| InitialServiceManager ism = orbInstance_.getInitialServiceManager(); |
| |
| // |
| // Create the Root POAManager |
| // |
| org.apache.yoko.orb.OBPortableServer.POAManagerFactory factory = null; |
| try { |
| factory = org.apache.yoko.orb.OBPortableServer.POAManagerFactoryHelper.narrow(ism.resolveInitialReferences("POAManagerFactory")); |
| } catch (org.omg.CORBA.ORBPackage.InvalidName ex) { |
| Assert._OB_assert(ex); |
| } |
| |
| // |
| // First attempt to locate the root POAManager |
| // |
| org.apache.yoko.orb.OBPortableServer.POAManager manager = null; |
| |
| org.omg.PortableServer.POAManager[] managers = factory.list(); |
| for (int i = 0; i < managers.length; i++) { |
| if (managers[i].get_id().equals("RootPOAManager")) { |
| manager = (org.apache.yoko.orb.OBPortableServer.POAManager) managers[i]; |
| break; |
| } |
| } |
| |
| // |
| // If the root POAManager doesn't exist then create it |
| // |
| if (manager == null) { |
| try { |
| org.omg.CORBA.Policy[] emptyPl = new org.omg.CORBA.Policy[0]; |
| manager = (org.apache.yoko.orb.OBPortableServer.POAManager) (factory.create_POAManager("RootPOAManager", emptyPl)); |
| } catch (org.omg.PortableServer.POAManagerFactoryPackage.ManagerAlreadyExists ex) { |
| Assert._OB_assert(ex); |
| } |
| // catch(org.apache.yoko.orb.OCI.InvalidParam ex) |
| // { |
| // Logger logger = orbInstance_.getLogger(); |
| // String err = "invalid configuration parameter " + |
| // "for RootPOAManager: " + ex.reason; |
| // logger.error(err); |
| // throw new org.omg.CORBA.INITIALIZE(err); |
| // } |
| catch (org.omg.CORBA.PolicyError ex) { |
| // TODO : Is this correct? |
| Assert._OB_assert(ex); |
| } |
| } |
| |
| // |
| // Create the Root POA |
| // |
| org.apache.yoko.orb.OBPortableServer.POA_impl root = new org.apache.yoko.orb.OBPortableServer.POA_impl(orb, orbInstance_, serverId, manager); |
| root._OB_addPolicyFactory(); |
| rootPOA_ = root; |
| |
| try { |
| ism.addInitialReference("RootPOA", root, true); |
| } catch (org.omg.CORBA.ORBPackage.InvalidName ex) { |
| Assert._OB_assert(ex); |
| } |
| |
| // |
| // Ask the POAManagerFactory to initialize this servers connection |
| // to the IMR |
| // |
| // TODO-B3: Is there some other point that can be used to do this? |
| // |
| org.apache.yoko.orb.OBPortableServer.POAManagerFactory_impl factoryImpl = (org.apache.yoko.orb.OBPortableServer.POAManagerFactory_impl) factory; |
| factoryImpl._OB_initializeIMR(root, this); |
| } |
| } |