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 sun.misc.ManagedLocalsThread { 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 this.mediator = mediator ; 318 this.key = key ; 319 this.entry = entry; 320 this.servant = servant; 321 this.debug = debug ; 322 } 323 324 public void run() { 325 if (debug) { 326 ORBUtility.dprint( this, "Calling Etherealizer.run on key " + 327 key ) ; 328 } 329 330 try { 331 try { 332 mediator.activator.etherealize( key.id, mediator.poa, servant, 333 false, mediator.activeObjectMap.hasMultipleIDs( entry ) ); 334 } catch (Exception exc) { 335 // ignore all exceptions 336 } 337 338 try { 339 mediator.poa.lock() ; 340 341 entry.etherealizeComplete() ; 342 mediator.activeObjectMap.remove( key ) ; 343 344 POAManagerImpl pm = (POAManagerImpl)mediator.poa.the_POAManager() ; 345 POAFactory factory = pm.getFactory() ; 346 factory.unregisterPOAForServant( mediator.poa, servant); 347 } finally { 348 mediator.poa.unlock() ; 349 } 350 } finally { 351 if (debug) { 352 ORBUtility.dprint( this, "Exiting Etherealizer.run" ) ; 353 } 354 } 355 } 356 } 357 358 public void deactivateHelper( ActiveObjectMap.Key key, AOMEntry entry, 359 Servant servant ) throws ObjectNotActive, WrongPolicy 360 { 361 if (activator == null) 362 throw poa.invocationWrapper().poaNoServantManager() ; 363 364 Etherealizer eth = new Etherealizer( this, key, entry, servant, poa.getDebug() ) ; 365 entry.startEtherealize( eth ) ; 366 } 367 368 public Servant idToServant( byte[] id ) 369 throws WrongPolicy, ObjectNotActive 370 { 371 ActiveObjectMap.Key key = new ActiveObjectMap.Key( id ) ; 372 AOMEntry entry = activeObjectMap.get(key); 373 374 Servant servant = activeObjectMap.getServant( entry ) ; 375 if (servant != null) 376 return servant ; 377 else 378 throw new ObjectNotActive() ; 379 } 380 }