1 /*
   2  * Copyright (c) 2002, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.corba.se.impl.oa.poa ;
  27 
  28 import java.util.Set ;
  29 import org.omg.CORBA.SystemException ;
  30 
  31 import org.omg.PortableServer.ServantActivator ;
  32 import org.omg.PortableServer.Servant ;
  33 import org.omg.PortableServer.ServantManager ;
  34 import org.omg.PortableServer.ForwardRequest ;
  35 import org.omg.PortableServer.POAPackage.WrongPolicy ;
  36 import org.omg.PortableServer.POAPackage.ObjectNotActive ;
  37 import org.omg.PortableServer.POAPackage.ServantNotActive ;
  38 import org.omg.PortableServer.POAPackage.ObjectAlreadyActive ;
  39 import org.omg.PortableServer.POAPackage.ServantAlreadyActive ;
  40 import org.omg.PortableServer.POAPackage.NoServant ;
  41 
  42 import com.sun.corba.se.impl.orbutil.concurrent.SyncUtil ;
  43 import com.sun.corba.se.impl.orbutil.ORBUtility ;
  44 import com.sun.corba.se.impl.orbutil.ORBConstants ;
  45 
  46 import com.sun.corba.se.impl.oa.NullServantImpl ;
  47 
  48 import com.sun.corba.se.impl.javax.rmi.CORBA.Util ;
  49 
  50 import com.sun.corba.se.spi.oa.OAInvocationInfo ;
  51 import com.sun.corba.se.spi.oa.NullServant ;
  52 
  53 /** Implementation of POARequesHandler that provides policy specific
  54  * operations on the POA.
  55  */
  56 public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R {
  57     protected ServantActivator activator ;
  58 
  59     POAPolicyMediatorImpl_R_USM( Policies policies, POAImpl poa )
  60     {
  61         // assert policies.retainServants()
  62         super( policies, poa ) ;
  63         activator = null ;
  64 
  65         if (!policies.useServantManager())
  66             throw poa.invocationWrapper().policyMediatorBadPolicyInFactory() ;
  67     }
  68 
  69     /* This handles a rather subtle bug (4939892).  The problem is that
  70      * enter will wait on the entry if it is being etherealized.  When the
  71      * deferred state transition completes, the entry is no longer in the
  72      * AOM, and so we need to get a new entry, otherwise activator.incarnate
  73      * will be called twice, once for the old entry, and again when a new
  74      * entry is created.  This fix also required extending the FSM StateEngine
  75      * to allow actions to throw exceptions, and adding a new state in the
  76      * AOMEntry FSM to detect this condition.
  77      */
  78     private AOMEntry enterEntry( ActiveObjectMap.Key key )
  79     {
  80         AOMEntry result = null ;
  81         boolean failed ;
  82         do {
  83             failed = false ;
  84             result = activeObjectMap.get(key) ;
  85 
  86             try {
  87                 result.enter() ;
  88             } catch (Exception exc) {
  89                 failed = true ;
  90             }
  91         } while (failed) ;
  92 
  93         return result ;
  94     }
  95 
  96     protected java.lang.Object internalGetServant( byte[] id,
  97         String operation ) throws ForwardRequest
  98     {
  99         if (poa.getDebug()) {
 100             ORBUtility.dprint( this,
 101                 "Calling POAPolicyMediatorImpl_R_USM.internalGetServant " +
 102                 "for poa " + poa + " operation=" + operation ) ;
 103         }
 104 
 105         try {
 106             ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
 107             AOMEntry entry = enterEntry(key) ;
 108             java.lang.Object servant = activeObjectMap.getServant( entry ) ;
 109             if (servant != null) {
 110                 if (poa.getDebug()) {
 111                     ORBUtility.dprint( this,
 112                         "internalGetServant: servant already activated" ) ;
 113                 }
 114 
 115                 return servant ;
 116             }
 117 
 118             if (activator == null) {
 119                 if (poa.getDebug()) {
 120                     ORBUtility.dprint( this,
 121                         "internalGetServant: no servant activator in POA" ) ;
 122                 }
 123 
 124                 entry.incarnateFailure() ;
 125                 throw poa.invocationWrapper().poaNoServantManager() ;
 126             }
 127 
 128             // Drop the POA lock during the incarnate call and
 129             // re-acquire it afterwards.  The entry state machine
 130             // prevents more than one thread from executing the
 131             // incarnate method at a time within the same POA.
 132             try {
 133                 if (poa.getDebug()) {
 134                     ORBUtility.dprint( this,
 135                         "internalGetServant: upcall to incarnate" ) ;
 136                 }
 137 
 138                 poa.unlock() ;
 139 
 140                 servant = activator.incarnate(id, poa);
 141 
 142                 if (servant == null)
 143                     servant = new NullServantImpl(
 144                         poa.omgInvocationWrapper().nullServantReturned() ) ;
 145             } catch (ForwardRequest freq) {
 146                 if (poa.getDebug()) {
 147                     ORBUtility.dprint( this,
 148                         "internalGetServant: incarnate threw ForwardRequest" ) ;
 149                 }
 150 
 151                 throw freq ;
 152             } catch (SystemException exc) {
 153                 if (poa.getDebug()) {
 154                     ORBUtility.dprint( this,
 155                         "internalGetServant: incarnate threw SystemException " + exc ) ;
 156                 }
 157 
 158                 throw exc ;
 159             } catch (Throwable exc) {
 160                 if (poa.getDebug()) {
 161                     ORBUtility.dprint( this,
 162                         "internalGetServant: incarnate threw Throwable " + exc ) ;
 163                 }
 164 
 165                 throw poa.invocationWrapper().poaServantActivatorLookupFailed(
 166                     exc ) ;
 167             } finally {
 168                 poa.lock() ;
 169 
 170                 // servant == null means incarnate threw an exception,
 171                 // while servant instanceof NullServant means incarnate returned a
 172                 // null servant.  Either case is an incarnate failure to the
 173                 // entry state machine.
 174                 if ((servant == null) || (servant instanceof NullServant)) {
 175                     if (poa.getDebug()) {
 176                         ORBUtility.dprint( this,
 177                             "internalGetServant: incarnate failed" ) ;
 178                     }
 179 
 180                     // XXX Does the AOM leak in this case? Yes,
 181                     // but the problem is hard to fix.  There may be
 182                     // a number of threads waiting for the state to change
 183                     // from INCARN to something else, which is VALID or
 184                     // INVALID, depending on the incarnate result.
 185                     // The activeObjectMap.get() call above creates an
 186                     // ActiveObjectMap.Entry if one does not already exist,
 187                     // and stores it in the keyToEntry map in the AOM.
 188                     entry.incarnateFailure() ;
 189                 } else {
 190                     // here check for unique_id policy, and if the servant
 191                     // is already registered for a different ID, then throw
 192                     // OBJ_ADAPTER exception, else activate it. Section 11.3.5.1
 193                     // 99-10-07.pdf
 194                     if (isUnique) {
 195                         // check if the servant already is associated with some id
 196                         if (activeObjectMap.contains((Servant)servant)) {
 197                             if (poa.getDebug()) {
 198                                 ORBUtility.dprint( this,
 199                                     "internalGetServant: servant already assigned to ID" ) ;
 200                             }
 201 
 202                             entry.incarnateFailure() ;
 203                             throw poa.invocationWrapper().poaServantNotUnique() ;
 204                         }
 205                     }
 206 
 207                     if (poa.getDebug()) {
 208                         ORBUtility.dprint( this,
 209                             "internalGetServant: incarnate complete" ) ;
 210                     }
 211 
 212                     entry.incarnateComplete() ;
 213                     activateServant(key, entry, (Servant)servant);
 214                 }
 215             }
 216 
 217             return servant ;
 218         } finally {
 219             if (poa.getDebug()) {
 220                 ORBUtility.dprint( this,
 221                     "Exiting POAPolicyMediatorImpl_R_USM.internalGetServant " +
 222                     "for poa " + poa ) ;
 223             }
 224         }
 225     }
 226 
 227     public void returnServant()
 228     {
 229         OAInvocationInfo info = orb.peekInvocationInfo();
 230         byte[] id = info.id() ;
 231         ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
 232         AOMEntry entry = activeObjectMap.get( key ) ;
 233         entry.exit() ;
 234     }
 235 
 236     public void etherealizeAll()
 237     {
 238         if (activator != null)  {
 239             Set keySet = activeObjectMap.keySet() ;
 240 
 241             // Copy the elements in the set to an array to avoid
 242             // changes in the set due to concurrent modification
 243             ActiveObjectMap.Key[] keys =
 244                 (ActiveObjectMap.Key[])keySet.toArray(
 245                     new ActiveObjectMap.Key[ keySet.size() ] ) ;
 246 
 247             for (int ctr=0; ctr<keySet.size(); ctr++) {
 248                 ActiveObjectMap.Key key = keys[ctr] ;
 249                 AOMEntry entry = activeObjectMap.get( key ) ;
 250                 Servant servant = activeObjectMap.getServant( entry ) ;
 251                 if (servant != null) {
 252                     boolean remainingActivations =
 253                         activeObjectMap.hasMultipleIDs(entry) ;
 254 
 255                     // Here we etherealize in the thread that called this
 256                     // method, rather than etherealizing in a new thread
 257                     // as in the deactivate case.  We still inform the
 258                     // entry state machine so that only one thread at a
 259                     // time can call the etherealize method.
 260                     entry.startEtherealize( null ) ;
 261                     try {
 262                         poa.unlock() ;
 263                         try {
 264                             activator.etherealize(key.id, poa, servant, true,
 265                                 remainingActivations);
 266                         } catch (Exception exc) {
 267                             // ignore all exceptions
 268                         }
 269                     } finally {
 270                         poa.lock() ;
 271                         entry.etherealizeComplete() ;
 272                     }
 273                 }
 274             }
 275         }
 276     }
 277 
 278     public ServantManager getServantManager() throws WrongPolicy
 279     {
 280         return activator;
 281     }
 282 
 283     public void setServantManager(
 284         ServantManager servantManager ) throws WrongPolicy
 285     {
 286         if (activator != null)
 287             throw poa.invocationWrapper().servantManagerAlreadySet() ;
 288 
 289         if (servantManager instanceof ServantActivator)
 290             activator = (ServantActivator)servantManager;
 291         else
 292             throw poa.invocationWrapper().servantManagerBadType() ;
 293     }
 294 
 295     public Servant getDefaultServant() throws NoServant, WrongPolicy
 296     {
 297         throw new WrongPolicy();
 298     }
 299 
 300     public void setDefaultServant( Servant servant ) throws WrongPolicy
 301     {
 302         throw new WrongPolicy();
 303     }
 304 
 305     class Etherealizer extends Thread {
 306         private POAPolicyMediatorImpl_R_USM mediator ;
 307         private ActiveObjectMap.Key key ;
 308         private AOMEntry entry ;
 309         private Servant servant ;
 310         private boolean debug ;
 311 
 312 
 313         public Etherealizer( POAPolicyMediatorImpl_R_USM mediator,
 314             ActiveObjectMap.Key key, AOMEntry entry, Servant servant,
 315             boolean debug )
 316         {
 317             super(null, null, "PAO-Etherealizer-Thread", 0, false);
 318             this.mediator = mediator ;
 319             this.key = key ;
 320             this.entry = entry;
 321             this.servant = servant;
 322             this.debug = debug ;
 323         }
 324 
 325         public void run() {
 326             if (debug) {
 327                 ORBUtility.dprint( this, "Calling Etherealizer.run on key " +
 328                     key ) ;
 329             }
 330 
 331             try {
 332                 try {
 333                     mediator.activator.etherealize( key.id, mediator.poa, servant,
 334                         false, mediator.activeObjectMap.hasMultipleIDs( entry ) );
 335                 } catch (Exception exc) {
 336                     // ignore all exceptions
 337                 }
 338 
 339                 try {
 340                     mediator.poa.lock() ;
 341 
 342                     entry.etherealizeComplete() ;
 343                     mediator.activeObjectMap.remove( key ) ;
 344 
 345                     POAManagerImpl pm = (POAManagerImpl)mediator.poa.the_POAManager() ;
 346                     POAFactory factory = pm.getFactory() ;
 347                     factory.unregisterPOAForServant( mediator.poa, servant);
 348                 } finally {
 349                     mediator.poa.unlock() ;
 350                 }
 351             } finally {
 352                 if (debug) {
 353                     ORBUtility.dprint( this, "Exiting Etherealizer.run" ) ;
 354                 }
 355             }
 356         }
 357     }
 358 
 359     public void deactivateHelper( ActiveObjectMap.Key key, AOMEntry entry,
 360         Servant servant ) throws ObjectNotActive, WrongPolicy
 361     {
 362         if (activator == null)
 363             throw poa.invocationWrapper().poaNoServantManager() ;
 364 
 365         Etherealizer eth = new Etherealizer( this, key, entry, servant, poa.getDebug() ) ;
 366         entry.startEtherealize( eth ) ;
 367     }
 368 
 369     public Servant idToServant( byte[] id )
 370         throws WrongPolicy, ObjectNotActive
 371     {
 372         ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
 373         AOMEntry entry = activeObjectMap.get(key);
 374 
 375         Servant servant = activeObjectMap.getServant( entry ) ;
 376         if (servant != null)
 377             return servant ;
 378         else
 379             throw new ObjectNotActive() ;
 380     }
 381 }