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 import com.sun.corba.se.impl.transport.ManagedLocalsThread;
  53 
  54 /** Implementation of POARequesHandler that provides policy specific
  55  * operations on the POA.
  56  */
  57 public class POAPolicyMediatorImpl_R_USM extends POAPolicyMediatorBase_R {
  58     protected ServantActivator activator ;
  59 
  60     POAPolicyMediatorImpl_R_USM( Policies policies, POAImpl poa )
  61     {
  62         // assert policies.retainServants()
  63         super( policies, poa ) ;
  64         activator = null ;
  65 
  66         if (!policies.useServantManager())
  67             throw poa.invocationWrapper().policyMediatorBadPolicyInFactory() ;
  68     }
  69 
  70     /* This handles a rather subtle bug (4939892).  The problem is that
  71      * enter will wait on the entry if it is being etherealized.  When the
  72      * deferred state transition completes, the entry is no longer in the
  73      * AOM, and so we need to get a new entry, otherwise activator.incarnate
  74      * will be called twice, once for the old entry, and again when a new
  75      * entry is created.  This fix also required extending the FSM StateEngine
  76      * to allow actions to throw exceptions, and adding a new state in the
  77      * AOMEntry FSM to detect this condition.
  78      */
  79     private AOMEntry enterEntry( ActiveObjectMap.Key key )
  80     {
  81         AOMEntry result = null ;
  82         boolean failed ;
  83         do {
  84             failed = false ;
  85             result = activeObjectMap.get(key) ;
  86 
  87             try {
  88                 result.enter() ;
  89             } catch (Exception exc) {
  90                 failed = true ;
  91             }
  92         } while (failed) ;
  93 
  94         return result ;
  95     }
  96 
  97     protected java.lang.Object internalGetServant( byte[] id,
  98         String operation ) throws ForwardRequest
  99     {
 100         if (poa.getDebug()) {
 101             ORBUtility.dprint( this,
 102                 "Calling POAPolicyMediatorImpl_R_USM.internalGetServant " +
 103                 "for poa " + poa + " operation=" + operation ) ;
 104         }
 105 
 106         try {
 107             ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
 108             AOMEntry entry = enterEntry(key) ;
 109             java.lang.Object servant = activeObjectMap.getServant( entry ) ;
 110             if (servant != null) {
 111                 if (poa.getDebug()) {
 112                     ORBUtility.dprint( this,
 113                         "internalGetServant: servant already activated" ) ;
 114                 }
 115 
 116                 return servant ;
 117             }
 118 
 119             if (activator == null) {
 120                 if (poa.getDebug()) {
 121                     ORBUtility.dprint( this,
 122                         "internalGetServant: no servant activator in POA" ) ;
 123                 }
 124 
 125                 entry.incarnateFailure() ;
 126                 throw poa.invocationWrapper().poaNoServantManager() ;
 127             }
 128 
 129             // Drop the POA lock during the incarnate call and
 130             // re-acquire it afterwards.  The entry state machine
 131             // prevents more than one thread from executing the
 132             // incarnate method at a time within the same POA.
 133             try {
 134                 if (poa.getDebug()) {
 135                     ORBUtility.dprint( this,
 136                         "internalGetServant: upcall to incarnate" ) ;
 137                 }
 138 
 139                 poa.unlock() ;
 140 
 141                 servant = activator.incarnate(id, poa);
 142 
 143                 if (servant == null)
 144                     servant = new NullServantImpl(
 145                         poa.omgInvocationWrapper().nullServantReturned() ) ;
 146             } catch (ForwardRequest freq) {
 147                 if (poa.getDebug()) {
 148                     ORBUtility.dprint( this,
 149                         "internalGetServant: incarnate threw ForwardRequest" ) ;
 150                 }
 151 
 152                 throw freq ;
 153             } catch (SystemException exc) {
 154                 if (poa.getDebug()) {
 155                     ORBUtility.dprint( this,
 156                         "internalGetServant: incarnate threw SystemException " + exc ) ;
 157                 }
 158 
 159                 throw exc ;
 160             } catch (Throwable exc) {
 161                 if (poa.getDebug()) {
 162                     ORBUtility.dprint( this,
 163                         "internalGetServant: incarnate threw Throwable " + exc ) ;
 164                 }
 165 
 166                 throw poa.invocationWrapper().poaServantActivatorLookupFailed(
 167                     exc ) ;
 168             } finally {
 169                 poa.lock() ;
 170 
 171                 // servant == null means incarnate threw an exception,
 172                 // while servant instanceof NullServant means incarnate returned a
 173                 // null servant.  Either case is an incarnate failure to the
 174                 // entry state machine.
 175                 if ((servant == null) || (servant instanceof NullServant)) {
 176                     if (poa.getDebug()) {
 177                         ORBUtility.dprint( this,
 178                             "internalGetServant: incarnate failed" ) ;
 179                     }
 180 
 181                     // XXX Does the AOM leak in this case? Yes,
 182                     // but the problem is hard to fix.  There may be
 183                     // a number of threads waiting for the state to change
 184                     // from INCARN to something else, which is VALID or
 185                     // INVALID, depending on the incarnate result.
 186                     // The activeObjectMap.get() call above creates an
 187                     // ActiveObjectMap.Entry if one does not already exist,
 188                     // and stores it in the keyToEntry map in the AOM.
 189                     entry.incarnateFailure() ;
 190                 } else {
 191                     // here check for unique_id policy, and if the servant
 192                     // is already registered for a different ID, then throw
 193                     // OBJ_ADAPTER exception, else activate it. Section 11.3.5.1
 194                     // 99-10-07.pdf
 195                     if (isUnique) {
 196                         // check if the servant already is associated with some id
 197                         if (activeObjectMap.contains((Servant)servant)) {
 198                             if (poa.getDebug()) {
 199                                 ORBUtility.dprint( this,
 200                                     "internalGetServant: servant already assigned to ID" ) ;
 201                             }
 202 
 203                             entry.incarnateFailure() ;
 204                             throw poa.invocationWrapper().poaServantNotUnique() ;
 205                         }
 206                     }
 207 
 208                     if (poa.getDebug()) {
 209                         ORBUtility.dprint( this,
 210                             "internalGetServant: incarnate complete" ) ;
 211                     }
 212 
 213                     entry.incarnateComplete() ;
 214                     activateServant(key, entry, (Servant)servant);
 215                 }
 216             }
 217 
 218             return servant ;
 219         } finally {
 220             if (poa.getDebug()) {
 221                 ORBUtility.dprint( this,
 222                     "Exiting POAPolicyMediatorImpl_R_USM.internalGetServant " +
 223                     "for poa " + poa ) ;
 224             }
 225         }
 226     }
 227 
 228     public void returnServant()
 229     {
 230         OAInvocationInfo info = orb.peekInvocationInfo();
 231         byte[] id = info.id() ;
 232         ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ;
 233         AOMEntry entry = activeObjectMap.get( key ) ;
 234         entry.exit() ;
 235     }
 236 
 237     public void etherealizeAll()
 238     {
 239         if (activator != null)  {
 240             Set keySet = activeObjectMap.keySet() ;
 241 
 242             // Copy the elements in the set to an array to avoid
 243             // changes in the set due to concurrent modification
 244             ActiveObjectMap.Key[] keys =
 245                 (ActiveObjectMap.Key[])keySet.toArray(
 246                     new ActiveObjectMap.Key[ keySet.size() ] ) ;
 247 
 248             for (int ctr=0; ctr<keySet.size(); ctr++) {
 249                 ActiveObjectMap.Key key = keys[ctr] ;
 250                 AOMEntry entry = activeObjectMap.get( key ) ;
 251                 Servant servant = activeObjectMap.getServant( entry ) ;
 252                 if (servant != null) {
 253                     boolean remainingActivations =
 254                         activeObjectMap.hasMultipleIDs(entry) ;
 255 
 256                     // Here we etherealize in the thread that called this
 257                     // method, rather than etherealizing in a new thread
 258                     // as in the deactivate case.  We still inform the
 259                     // entry state machine so that only one thread at a
 260                     // time can call the etherealize method.
 261                     entry.startEtherealize( null ) ;
 262                     try {
 263                         poa.unlock() ;
 264                         try {
 265                             activator.etherealize(key.id, poa, servant, true,
 266                                 remainingActivations);
 267                         } catch (Exception exc) {
 268                             // ignore all exceptions
 269                         }
 270                     } finally {
 271                         poa.lock() ;
 272                         entry.etherealizeComplete() ;
 273                     }
 274                 }
 275             }
 276         }
 277     }
 278 
 279     public ServantManager getServantManager() throws WrongPolicy
 280     {
 281         return activator;
 282     }
 283 
 284     public void setServantManager(
 285         ServantManager servantManager ) throws WrongPolicy
 286     {
 287         if (activator != null)
 288             throw poa.invocationWrapper().servantManagerAlreadySet() ;
 289 
 290         if (servantManager instanceof ServantActivator)
 291             activator = (ServantActivator)servantManager;
 292         else
 293             throw poa.invocationWrapper().servantManagerBadType() ;
 294     }
 295 
 296     public Servant getDefaultServant() throws NoServant, WrongPolicy
 297     {
 298         throw new WrongPolicy();
 299     }
 300 
 301     public void setDefaultServant( Servant servant ) throws WrongPolicy
 302     {
 303         throw new WrongPolicy();
 304     }
 305 
 306     class Etherealizer extends ManagedLocalsThread {
 307         private POAPolicyMediatorImpl_R_USM mediator ;
 308         private ActiveObjectMap.Key key ;
 309         private AOMEntry entry ;
 310         private Servant servant ;
 311         private boolean debug ;
 312 
 313 
 314         public Etherealizer( POAPolicyMediatorImpl_R_USM mediator,
 315             ActiveObjectMap.Key key, AOMEntry entry, Servant servant,
 316             boolean debug )
 317         {
 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 }