1. /*
  2. * @(#)Util.java 1.27 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. /*
  8. * Licensed Materials - Property of IBM
  9. * RMI-IIOP v1.0
  10. * Copyright IBM Corp. 1998 1999 All Rights Reserved
  11. *
  12. * US Government Users Restricted Rights - Use, duplication or
  13. * disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  14. */
  15. package com.sun.corba.se.internal.javax.rmi.CORBA; // Util (sed marker, don't remove!)
  16. import java.rmi.RemoteException;
  17. import javax.rmi.CORBA.ValueHandler;
  18. import org.omg.CORBA.ORB;
  19. import org.omg.CORBA.SystemException;
  20. import org.omg.CORBA.Any;
  21. import org.omg.CORBA.portable.InputStream;
  22. import org.omg.CORBA.portable.OutputStream;
  23. import org.omg.CORBA.portable.ObjectImpl;
  24. import org.omg.CORBA.TCKind;
  25. import javax.rmi.CORBA.Tie;
  26. import java.util.Hashtable;
  27. import java.util.Enumeration;
  28. import java.io.Serializable;
  29. import java.rmi.MarshalException;
  30. import java.rmi.NoSuchObjectException;
  31. import java.rmi.AccessException;
  32. import java.rmi.Remote;
  33. import java.rmi.ServerError;
  34. import java.rmi.ServerException;
  35. import java.rmi.ServerRuntimeException;
  36. import javax.transaction.TransactionRequiredException;
  37. import javax.transaction.TransactionRolledbackException;
  38. import javax.transaction.InvalidTransactionException;
  39. import org.omg.CORBA.COMM_FAILURE;
  40. import org.omg.CORBA.BAD_PARAM;
  41. import org.omg.CORBA.INV_OBJREF;
  42. import org.omg.CORBA.NO_PERMISSION;
  43. import org.omg.CORBA.MARSHAL;
  44. import org.omg.CORBA.OBJECT_NOT_EXIST;
  45. import org.omg.CORBA.TRANSACTION_REQUIRED;
  46. import org.omg.CORBA.TRANSACTION_ROLLEDBACK;
  47. import org.omg.CORBA.INVALID_TRANSACTION;
  48. import org.omg.CORBA.BAD_OPERATION;
  49. import org.omg.CORBA.CompletionStatus;
  50. import org.omg.CORBA.portable.UnknownException;
  51. import com.sun.corba.se.internal.io.ValueHandlerImpl;
  52. import com.sun.corba.se.internal.util.Utility;
  53. import com.sun.corba.se.internal.util.IdentityHashtable;
  54. import com.sun.corba.se.internal.util.JDKBridge;
  55. import java.io.NotSerializableException;
  56. import java.rmi.UnexpectedException;
  57. import java.rmi.MarshalException;
  58. import java.rmi.server.RMIClassLoader;
  59. import java.security.AccessController;
  60. import java.security.PrivilegedAction;
  61. import java.util.Properties;
  62. /**
  63. * Provides utility methods that can be used by stubs and ties to
  64. * perform common operations.
  65. */
  66. public abstract class Util implements javax.rmi.CORBA.UtilDelegate {
  67. // Runs as long as there are exportedServants
  68. private static KeepAlive keepAlive = null;
  69. // Maps targets to ties.
  70. private static IdentityHashtable exportedServants = new IdentityHashtable();
  71. private static ValueHandlerImpl valueHandlerSingleton = new ValueHandlerImpl();
  72. public abstract RemoteException mapSystemException(SystemException ex);
  73. public abstract void writeAny(OutputStream out, Object obj);
  74. /**
  75. * Reads a java.lang.Object as a CORBA any.
  76. * @param in the stream from which to read the any.
  77. * @return the object read from the stream.
  78. */
  79. public Object readAny(InputStream in) {
  80. //d11638 Read the Any
  81. Any any = in.read_any();
  82. if ( any.type().kind().value() == TCKind._tk_objref )
  83. return any.extract_Object ();
  84. else
  85. return any.extract_Value();
  86. }
  87. /**
  88. * Writes a java.lang.Object as a CORBA Object. If <code>obj</code> is
  89. * an exported RMI-IIOP server object, the tie is found
  90. * and wired to <code>obj</code>, then written to <code>out.write_Object(org.omg.CORBA.Object)</code>.
  91. * If <code>obj</code> is a CORBA Object, it is written to
  92. * <code>out.write_Object(org.omg.CORBA.Object)</code>.
  93. * @param out the stream in which to write the object.
  94. * @param obj the object to write.
  95. */
  96. public void writeRemoteObject(OutputStream out,
  97. java.lang.Object obj) {
  98. // Make sure we have a connected object, then
  99. // write it out...
  100. Object newObj = Utility.autoConnect(obj,out.orb(),false);
  101. out.write_Object((org.omg.CORBA.Object)newObj);
  102. }
  103. /**
  104. * Writes a java.lang.Object as either a value or a CORBA Object.
  105. * If <code>obj</code> is a value object or a stub object, it is written to
  106. * <code>out.write_abstract_interface(java.lang.Object)</code>. If <code>obj</code> is an exported
  107. * RMI-IIOP server object, the tie is found and wired to <code>obj</code>,
  108. * then written to <code>out.write_abstract_interface(java.lang.Object)</code>.
  109. * @param out the stream in which to write the object.
  110. * @param obj the object to write.
  111. */
  112. public void writeAbstractObject(OutputStream out,
  113. java.lang.Object obj) {
  114. // Make sure we have a connected object, then
  115. // write it out...
  116. Object newObj = Utility.autoConnect(obj,out.orb(),false);
  117. ((org.omg.CORBA_2_3.portable.OutputStream)out).write_abstract_interface(newObj);
  118. }
  119. /**
  120. * Registers a target for a tie. Adds the tie to an internal table and calls
  121. * {@link Tie#setTarget} on the tie object.
  122. * @param tie the tie to register.
  123. * @param target the target for the tie.
  124. */
  125. public void registerTarget(javax.rmi.CORBA.Tie tie,
  126. java.rmi.Remote target) {
  127. synchronized (exportedServants) {
  128. // Do we already have this target registered?
  129. if (lookupTie(target) == null) {
  130. // No, so register it and set the target...
  131. exportedServants.put(target,tie);
  132. tie.setTarget(target);
  133. // Do we need to instantiate our keep-alive thread?
  134. if (keepAlive == null) {
  135. // Yes. Instantiate our keep-alive thread and start
  136. // it up...
  137. keepAlive = (KeepAlive)AccessController.doPrivileged(new PrivilegedAction() {
  138. public java.lang.Object run() {
  139. return new KeepAlive();
  140. }
  141. });
  142. keepAlive.start();
  143. }
  144. }
  145. }
  146. }
  147. /**
  148. * Removes the associated tie from an internal table and calls {@link Tie#deactivate}
  149. * to deactivate the object.
  150. * @param target the object to unexport.
  151. */
  152. public void unexportObject(java.rmi.Remote target)
  153. throws java.rmi.NoSuchObjectException
  154. {
  155. synchronized (exportedServants) {
  156. Tie cachedTie = lookupTie(target);
  157. if (cachedTie != null) {
  158. exportedServants.remove(target);
  159. Utility.purgeStubForTie(cachedTie);
  160. Utility.purgeTieAndServant(cachedTie);
  161. try {
  162. cleanUpTie(cachedTie);
  163. } catch (BAD_OPERATION e) {
  164. } catch (org.omg.CORBA.OBJ_ADAPTER e) {
  165. // This can happen when the target was never associated with a POA.
  166. // We can safely ignore this case.
  167. }
  168. // Is it time to shut down our keep alive thread?
  169. if (exportedServants.isEmpty()) {
  170. // Yep, so shut it down...
  171. keepAlive.quit();
  172. keepAlive = null;
  173. }
  174. } else {
  175. throw new java.rmi.NoSuchObjectException("Tie not found" );
  176. }
  177. }
  178. }
  179. protected void unregisterTargetsForORB(ORB orb)
  180. {
  181. for (Enumeration e = exportedServants.keys(); e.hasMoreElements(); ) {
  182. java.lang.Object key = e.nextElement();
  183. Remote target = (Remote)(key instanceof Tie ? ((Tie)key).getTarget() : key);
  184. // Bug 4476347: BAD_OPERATION is thrown if the ties delegate isn't set.
  185. // We can ignore this because it means the tie is not connected to an ORB.
  186. try {
  187. if (orb == getTie(target).orb()) {
  188. try {
  189. unexportObject(target);
  190. } catch( java.rmi.NoSuchObjectException ex ) {
  191. // We neglect this exception if at all if it is
  192. // raised. It is not harmful.
  193. }
  194. }
  195. } catch (BAD_OPERATION bad) { /* Ignore */ }
  196. }
  197. }
  198. // Needed to be overridden by subclass in the POA package
  199. protected void cleanUpTie(Tie cachedTie)
  200. throws java.rmi.NoSuchObjectException
  201. {
  202. cachedTie.setTarget(null);
  203. cachedTie.deactivate();
  204. }
  205. /**
  206. * Returns the tie (if any) for a given target object.
  207. * @return the tie or null if no tie is registered for the given target.
  208. */
  209. public Tie getTie (Remote target) {
  210. synchronized (exportedServants) {
  211. return lookupTie(target);
  212. }
  213. }
  214. /**
  215. * An unsynchronized version of getTie() for internal use.
  216. */
  217. private static Tie lookupTie (Remote target) {
  218. Tie result = (Tie)exportedServants.get(target);
  219. if (result == null && target instanceof Tie) {
  220. if (exportedServants.contains(target)) {
  221. result = (Tie)target;
  222. }
  223. }
  224. return result;
  225. }
  226. /**
  227. * Returns a singleton instance of a class that implements the
  228. * {@link ValueHandler} interface.
  229. * @return a class which implements the ValueHandler interface.
  230. */
  231. public ValueHandler createValueHandler() {
  232. return valueHandlerSingleton;
  233. }
  234. /**
  235. * Returns the codebase, if any, for the given class.
  236. * @param clz the class to get a codebase for.
  237. * @return a space-separated list of URLs, or null.
  238. */
  239. public String getCodebase(java.lang.Class clz) {
  240. return RMIClassLoader.getClassAnnotation(clz);
  241. }
  242. /**
  243. * Returns a class instance for the specified class.
  244. * @param className the name of the class.
  245. * @param remoteCodebase a space-separated list of URLs at which
  246. * the class might be found. May be null.
  247. * @param loadingContext a class whose ClassLoader may be used to
  248. * load the class if all other methods fail.
  249. * @return the <code>Class</code> object representing the loaded class.
  250. * @exception ClassNotFoundException if class cannot be loaded.
  251. */
  252. public Class loadClass(String className,
  253. String remoteCodebase,
  254. ClassLoader loader)
  255. throws ClassNotFoundException {
  256. return JDKBridge.loadClass(className,remoteCodebase,loader);
  257. }
  258. /**
  259. * The <tt>isLocal</tt> method has the same semantics as the ObjectImpl._is_local
  260. * method, except that it can throw a RemoteException.
  261. * (no it doesn't but the spec says it should.)
  262. *
  263. * The <tt>_is_local()</tt> method is provided so that stubs may determine if a
  264. * particular object is implemented by a local servant and hence local
  265. * invocation APIs may be used.
  266. *
  267. * @param stub the stub to test.
  268. *
  269. * @return The <tt>_is_local()</tt> method returns true if
  270. * the servant incarnating the object is located in the same process as
  271. * the stub and they both share the same ORB instance. The <tt>_is_local()</tt>
  272. * method returns false otherwise. The default behavior of <tt>_is_local()</tt> is
  273. * to return false.
  274. *
  275. * @throws RemoteException The Java to IDL specification does to
  276. * specify the conditions that cause a RemoteException to be thrown.
  277. */
  278. public boolean isLocal(javax.rmi.CORBA.Stub stub) throws RemoteException {
  279. return false ;
  280. }
  281. /**
  282. * Wraps an exception thrown by an implementation
  283. * method. It returns the corresponding client-side exception.
  284. * @param orig the exception to wrap.
  285. * @return the wrapped exception.
  286. */
  287. public RemoteException wrapException(Throwable orig) {
  288. if (orig instanceof SystemException) {
  289. return mapSystemException((SystemException)orig);
  290. }
  291. if (orig instanceof Error) {
  292. return new ServerError("Error occurred in server thread",(Error)orig);
  293. } else if (orig instanceof RemoteException) {
  294. return new ServerException("RemoteException occurred in server thread",
  295. (Exception)orig);
  296. } else if (orig instanceof RuntimeException) {
  297. throw (RuntimeException) orig;
  298. }
  299. return new UnexpectedException(orig.toString());
  300. }
  301. /**
  302. * Copies or connects an array of objects. Used by local stubs
  303. * to copy any number of actual parameters, preserving sharing
  304. * across parameters as necessary to support RMI semantics.
  305. * @param obj the objects to copy or connect.
  306. * @param orb the ORB.
  307. * @return the copied or connected objects.
  308. * @exception RemoteException if any object could not be copied or connected.
  309. */
  310. public Object[] copyObjects (Object[] obj, ORB orb)
  311. throws RemoteException {
  312. boolean stringPresent = false;
  313. org.omg.CORBA_2_3.portable.OutputStream out = null;
  314. try {
  315. // Allocate a new array if we need to...
  316. if (obj.getClass().getComponentType() != Object.class) {
  317. Object[] orig = obj;
  318. obj = new Object[obj.length];
  319. System.arraycopy(orig,0,obj,0,obj.length);
  320. }
  321. // Decide what, if any, types need to be copied
  322. // and do so. Do not write Strings in this pass,
  323. // but connect any Remote objects...
  324. for (int i = 0; i < obj.length; i++) {
  325. Object it = obj[i];
  326. if (it == null) {
  327. // Do nothing
  328. } else if (it instanceof SystemException) {
  329. try {
  330. SystemException inEx = (SystemException)it;
  331. SystemException outEx = (SystemException)inEx.getClass().newInstance();
  332. outEx.minor = inEx.minor;
  333. outEx.completed = inEx.completed;
  334. obj[i] = outEx;
  335. } catch (Exception e) {
  336. throw new UnexpectedException(obj.toString());
  337. }
  338. } else if (it instanceof Remote) {
  339. // Make sure it is connected and converted to
  340. // a stub (if needed)...
  341. obj[i] = Utility.autoConnect(it,orb,true);
  342. } else if (it instanceof String) {
  343. stringPresent = true;
  344. } else if (it instanceof org.omg.CORBA.Object) {
  345. } else {
  346. // It's a value, so must be copied. First, make sure
  347. // we've got our output stream...
  348. if (out == null) {
  349. out = (org.omg.CORBA_2_3.portable.OutputStream)orb.create_output_stream();
  350. }
  351. // Now write it...
  352. out.write_value((Serializable)it);
  353. }
  354. }
  355. // Did we write anything? If not, we're done...
  356. if (out != null) {
  357. // Yes, did we find any strings? If so, they must also be
  358. // written...
  359. if (stringPresent) {
  360. for (int i = 0; i < obj.length; i++) {
  361. if (obj[i] instanceof String) {
  362. out.write_value((String)obj[i]);
  363. }
  364. }
  365. }
  366. // Ok, now read everything that we wrote back in
  367. // and update the array...
  368. org.omg.CORBA_2_3.portable.InputStream in =
  369. (org.omg.CORBA_2_3.portable.InputStream)out.create_input_stream();
  370. for (int i = 0; i < obj.length; i++) {
  371. Object it = obj[i];
  372. if (it == null) {
  373. } else if (it instanceof SystemException) {
  374. } else if (it instanceof Remote) {
  375. } else if (it instanceof String) {
  376. } else if (it instanceof org.omg.CORBA.Object) {
  377. } else {
  378. obj[i] = in.read_value();
  379. }
  380. }
  381. if (stringPresent) {
  382. for (int i = 0; i < obj.length; i++) {
  383. if (obj[i] instanceof String) {
  384. obj[i] = in.read_value();
  385. }
  386. }
  387. }
  388. }
  389. } catch (ClassCastException ex) {
  390. throw new MarshalException("Exception occurred in server thread",
  391. new NotSerializableException());
  392. } catch (SystemException ex) {
  393. throw mapSystemException(ex);
  394. }
  395. return obj;
  396. }
  397. /**
  398. * Copies or connects an object. Used by local stubs to copy
  399. * an actual parameter, result object, or exception.
  400. * @param obj the object to copy.
  401. * @param orb the ORB.
  402. * @return the copy or connected object.
  403. * @exception RemoteException if the object could not be copied or connected.
  404. */
  405. public Object copyObject (Object obj, ORB orb)
  406. throws RemoteException {
  407. // Is it null?
  408. if (obj == null) {
  409. // Yes, so do nothing...
  410. return obj;
  411. }
  412. // Is it a SystemException?
  413. if (obj instanceof SystemException) {
  414. // Yes, so copy it monomorphically...
  415. try {
  416. SystemException in = (SystemException)obj;
  417. SystemException out = (SystemException)in.getClass().newInstance();
  418. out.minor = in.minor;
  419. out.completed = in.completed;
  420. return out;
  421. } catch (Exception e) {
  422. throw new UnexpectedException(obj.toString());
  423. }
  424. }
  425. // Is it a String?
  426. if (obj instanceof String) {
  427. // Yes, so do nothing...
  428. return obj;
  429. }
  430. // Is it Remote?
  431. if (obj instanceof Remote) {
  432. // Yes, so make sure it is connected and converted
  433. // to a stub (if needed)...
  434. return Utility.autoConnect(obj,orb,true);
  435. }
  436. // Is it a CORBA object?
  437. if (obj instanceof org.omg.CORBA.Object) {
  438. // Yes, so do nothing...
  439. return obj;
  440. }
  441. // Is it a single-dimensional primitive array?
  442. Class componentType = obj.getClass().getComponentType();
  443. if (componentType != null && componentType.isPrimitive()) {
  444. // Yes, so clone it...
  445. if (componentType == boolean.class) return ((boolean[])obj).clone();
  446. if (componentType == byte.class) return ((byte[])obj).clone();
  447. if (componentType == char.class) return ((char[])obj).clone();
  448. if (componentType == short.class) return ((short[])obj).clone();
  449. if (componentType == int.class) return ((int[])obj).clone();
  450. if (componentType == long.class) return ((long[])obj).clone();
  451. if (componentType == float.class) return ((float[])obj).clone();
  452. if (componentType == double.class) return ((double[])obj).clone();
  453. }
  454. // Must be a value type. Note that types which are normally
  455. // marshalled as ANYs are handled here...
  456. try {
  457. org.omg.CORBA_2_3.portable.OutputStream out =
  458. (org.omg.CORBA_2_3.portable.OutputStream)orb.create_output_stream();
  459. out.write_value((Serializable)obj);
  460. org.omg.CORBA_2_3.portable.InputStream in =
  461. (org.omg.CORBA_2_3.portable.InputStream)out.create_input_stream();
  462. return in.read_value();
  463. } catch (ClassCastException ex) {
  464. throw new MarshalException("Exception occurred in server thread",
  465. new NotSerializableException());
  466. } catch (SystemException ex) {
  467. throw mapSystemException(ex);
  468. }
  469. }
  470. }
  471. class KeepAlive extends Thread {
  472. boolean quit = false;
  473. public KeepAlive () {
  474. setDaemon(false);
  475. }
  476. public synchronized void run () {
  477. while (!quit) {
  478. try {
  479. wait();
  480. } catch (InterruptedException e) {}
  481. }
  482. }
  483. public synchronized void quit () {
  484. quit = true;
  485. notifyAll();
  486. }
  487. }