1. /*
  2. * @(#)ServiceContexts.java 1.24 04/06/21
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.spi.servicecontext;
  8. import java.lang.reflect.InvocationTargetException ;
  9. import java.lang.reflect.Modifier ;
  10. import java.lang.reflect.Field ;
  11. import java.lang.reflect.Constructor ;
  12. import java.util.*;
  13. import org.omg.CORBA.OctetSeqHelper;
  14. import org.omg.CORBA.SystemException;
  15. import org.omg.CORBA.INTERNAL;
  16. import org.omg.CORBA.CompletionStatus;
  17. import org.omg.CORBA_2_3.portable.OutputStream ;
  18. import org.omg.CORBA_2_3.portable.InputStream ;
  19. import com.sun.org.omg.SendingContext.CodeBase;
  20. import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
  21. import com.sun.corba.se.spi.orb.ORB ;
  22. import com.sun.corba.se.spi.logging.CORBALogDomains;
  23. import com.sun.corba.se.spi.servicecontext.ServiceContext ;
  24. import com.sun.corba.se.spi.servicecontext.ServiceContextRegistry ;
  25. import com.sun.corba.se.spi.servicecontext.ServiceContextData ;
  26. import com.sun.corba.se.spi.servicecontext.UnknownServiceContext ;
  27. import com.sun.corba.se.impl.encoding.CDRInputStream;
  28. import com.sun.corba.se.impl.encoding.EncapsInputStream ;
  29. import com.sun.corba.se.impl.orbutil.ORBUtility ;
  30. import com.sun.corba.se.impl.util.Utility ;
  31. import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
  32. public class ServiceContexts {
  33. private static boolean isDebugging( OutputStream os )
  34. {
  35. ORB orb = (ORB)(os.orb()) ;
  36. if (orb==null)
  37. return false ;
  38. return orb.serviceContextDebugFlag ;
  39. }
  40. private static boolean isDebugging( InputStream is )
  41. {
  42. ORB orb = (ORB)(is.orb()) ;
  43. if (orb==null)
  44. return false ;
  45. return orb.serviceContextDebugFlag ;
  46. }
  47. private void dprint( String msg )
  48. {
  49. ORBUtility.dprint( this, msg ) ;
  50. }
  51. public static void writeNullServiceContext( OutputStream os )
  52. {
  53. if (isDebugging(os))
  54. ORBUtility.dprint( "ServiceContexts", "Writing null service context" ) ;
  55. os.write_long( 0 ) ;
  56. }
  57. /**
  58. * Given the input stream, this fills our service
  59. * context map. See the definition of scMap for
  60. * details. Creates a HashMap.
  61. *
  62. * Note that we don't actually unmarshal the
  63. * bytes of the service contexts here. That is
  64. * done when they are actually requested via
  65. * get(int).
  66. */
  67. private void createMapFromInputStream(InputStream is)
  68. {
  69. orb = (ORB)(is.orb()) ;
  70. if (orb.serviceContextDebugFlag)
  71. dprint( "Constructing ServiceContexts from input stream" ) ;
  72. int numValid = is.read_long() ;
  73. if (orb.serviceContextDebugFlag)
  74. dprint("Number of service contexts = " + numValid);
  75. for (int ctr = 0; ctr < numValid; ctr++) {
  76. int scId = is.read_long();
  77. if (orb.serviceContextDebugFlag)
  78. dprint("Reading service context id " + scId);
  79. byte[] data = OctetSeqHelper.read(is);
  80. if (orb.serviceContextDebugFlag)
  81. dprint("Service context" + scId + " length: " + data.length);
  82. scMap.put(new Integer(scId), data);
  83. }
  84. }
  85. public ServiceContexts( ORB orb )
  86. {
  87. this.orb = orb ;
  88. wrapper = ORBUtilSystemException.get( orb,
  89. CORBALogDomains.RPC_PROTOCOL ) ;
  90. addAlignmentOnWrite = false ;
  91. scMap = new HashMap();
  92. // Use the GIOP version of the ORB. Should
  93. // be specified in ServiceContext.
  94. // See REVISIT below concerning giopVersion.
  95. giopVersion = orb.getORBData().getGIOPVersion();
  96. codeBase = null ;
  97. }
  98. /**
  99. * Read the Service contexts from the input stream.
  100. */
  101. public ServiceContexts(InputStream s)
  102. {
  103. this( (ORB)(s.orb()) ) ;
  104. // We need to store this so that we can have access
  105. // to the CodeBase for unmarshaling possible
  106. // RMI-IIOP valuetype data within an encapsulation.
  107. // (Known case: UnknownExceptionInfo)
  108. codeBase = ((CDRInputStream)s).getCodeBase();
  109. createMapFromInputStream(s);
  110. // Fix for bug 4904723
  111. giopVersion = ((CDRInputStream)s).getGIOPVersion();
  112. }
  113. /**
  114. * Find the ServiceContextData for a given scId and unmarshal
  115. * the bytes.
  116. */
  117. private ServiceContext unmarshal(Integer scId, byte[] data) {
  118. ServiceContextRegistry scr = orb.getServiceContextRegistry();
  119. ServiceContextData scd = scr.findServiceContextData(scId.intValue());
  120. ServiceContext sc = null;
  121. if (scd == null) {
  122. if (orb.serviceContextDebugFlag) {
  123. dprint("Could not find ServiceContextData for "
  124. + scId
  125. + " using UnknownServiceContext");
  126. }
  127. sc = new UnknownServiceContext(scId.intValue(), data);
  128. } else {
  129. if (orb.serviceContextDebugFlag) {
  130. dprint("Found " + scd);
  131. }
  132. // REVISIT. GIOP version should be specified as
  133. // part of a service context's definition, so should
  134. // be accessible from ServiceContextData via
  135. // its ServiceContext implementation class.
  136. //
  137. // Since we don't have that, yet, I'm using the GIOP
  138. // version of the input stream, presuming that someone
  139. // can't send a service context of a later GIOP
  140. // version than its stream version.
  141. //
  142. // Note: As of Jan 2001, no standard OMG or Sun service contexts
  143. // ship wchar data or are defined as using anything but GIOP 1.0 CDR.
  144. EncapsInputStream eis
  145. = new EncapsInputStream(orb,
  146. data,
  147. data.length,
  148. giopVersion,
  149. codeBase);
  150. eis.consumeEndian();
  151. // Now the input stream passed to a ServiceContext
  152. // constructor is already the encapsulation input
  153. // stream with the endianness read off, so the
  154. // service context should just unmarshal its own
  155. // data.
  156. sc = scd.makeServiceContext(eis, giopVersion);
  157. if (sc == null)
  158. throw wrapper.svcctxUnmarshalError(
  159. CompletionStatus.COMPLETED_MAYBE);
  160. }
  161. return sc;
  162. }
  163. public void addAlignmentPadding()
  164. {
  165. // Make service context 12 bytes longer by adding
  166. // JAVAIDL_ALIGN_SERVICE_ID service context at end.
  167. // The exact length
  168. // must be >8 (minimum service context size) and
  169. // =4 mod 8, so 12 is the minimum.
  170. addAlignmentOnWrite = true ;
  171. }
  172. /**
  173. * Hopefully unused scid: This should be changed to a proper
  174. * VMCID aligned value. REVISIT!
  175. */
  176. private static final int JAVAIDL_ALIGN_SERVICE_ID = 0xbe1345cd ;
  177. /**
  178. * Write the service contexts to the output stream.
  179. *
  180. * If they haven't been unmarshaled, we don't have to
  181. * unmarshal them.
  182. */
  183. public void write(OutputStream os, GIOPVersion gv)
  184. {
  185. if (isDebugging(os)) {
  186. dprint( "Writing service contexts to output stream" ) ;
  187. Utility.printStackTrace() ;
  188. }
  189. int numsc = scMap.size();
  190. if (addAlignmentOnWrite) {
  191. if (isDebugging(os))
  192. dprint( "Adding alignment padding" ) ;
  193. numsc++ ;
  194. }
  195. if (isDebugging(os))
  196. dprint( "Service context has " + numsc + " components" ) ;
  197. os.write_long( numsc ) ;
  198. writeServiceContextsInOrder(os, gv);
  199. if (addAlignmentOnWrite) {
  200. if (isDebugging(os))
  201. dprint( "Writing alignment padding" ) ;
  202. os.write_long( JAVAIDL_ALIGN_SERVICE_ID ) ;
  203. os.write_long( 4 ) ;
  204. os.write_octet( (byte)0 ) ;
  205. os.write_octet( (byte)0 ) ;
  206. os.write_octet( (byte)0 ) ;
  207. os.write_octet( (byte)0 ) ;
  208. }
  209. if (isDebugging(os))
  210. dprint( "Service context writing complete" ) ;
  211. }
  212. /**
  213. * Write the service contexts in scMap in a desired order.
  214. * Right now, the only special case we have is UnknownExceptionInfo,
  215. * so I'm merely writing it last if present.
  216. */
  217. private void writeServiceContextsInOrder(OutputStream os, GIOPVersion gv) {
  218. // Temporarily remove this rather than check it per iteration
  219. Integer ueInfoId
  220. = new Integer(UEInfoServiceContext.SERVICE_CONTEXT_ID);
  221. Object unknownExceptionInfo = scMap.remove(ueInfoId);
  222. Iterator iter = scMap.keySet().iterator();
  223. while (iter.hasNext()) {
  224. Integer id = (Integer)iter.next();
  225. writeMapEntry(os, id, scMap.get(id), gv);
  226. }
  227. // Write the UnknownExceptionInfo service context last
  228. // (so it will be after the CodeBase) and restore it in
  229. // the map.
  230. if (unknownExceptionInfo != null) {
  231. writeMapEntry(os, ueInfoId, unknownExceptionInfo, gv);
  232. scMap.put(ueInfoId, unknownExceptionInfo);
  233. }
  234. }
  235. /**
  236. * Write the given entry from the scMap to the OutputStream.
  237. * See note on giopVersion. The service context should
  238. * know the GIOP version it is meant for.
  239. */
  240. private void writeMapEntry(OutputStream os, Integer id, Object scObj, GIOPVersion gv) {
  241. // If it's still in byte[] form, we don't need to
  242. // unmarshal it here, just copy the bytes into
  243. // the new stream.
  244. if (scObj instanceof byte[]) {
  245. if (isDebugging(os))
  246. dprint( "Writing service context bytes for id " + id);
  247. OctetSeqHelper.write(os, (byte[])scObj);
  248. } else {
  249. // We actually unmarshaled it into a ServiceContext
  250. // at some point.
  251. ServiceContext sc = (ServiceContext)scObj;
  252. if (isDebugging(os))
  253. dprint( "Writing service context " + sc ) ;
  254. sc.write(os, gv);
  255. }
  256. }
  257. /** Add a service context to the stream, if there is not already
  258. * a service context in this object with the same id as sc.
  259. */
  260. public void put( ServiceContext sc )
  261. {
  262. Integer id = new Integer(sc.getId());
  263. scMap.put(id, sc);
  264. }
  265. public void delete( int scId ) {
  266. this.delete(new Integer(scId));
  267. }
  268. public void delete(Integer id)
  269. {
  270. scMap.remove(id) ;
  271. }
  272. public ServiceContext get(int scId) {
  273. return this.get(new Integer(scId));
  274. }
  275. public ServiceContext get(Integer id)
  276. {
  277. Object result = scMap.get(id);
  278. if (result == null)
  279. return null ;
  280. // Lazy unmarshaling on first use.
  281. if (result instanceof byte[]) {
  282. ServiceContext sc = unmarshal(id, (byte[])result);
  283. scMap.put(id, sc);
  284. return sc;
  285. } else {
  286. return (ServiceContext)result;
  287. }
  288. }
  289. private ORB orb ;
  290. /**
  291. * Map of all ServiceContext objects in this container.
  292. *
  293. * Keys are java.lang.Integers for service context IDs.
  294. * Values are either instances of ServiceContext or the
  295. * unmarshaled byte arrays (unmarshaled on first use).
  296. *
  297. * This provides a mild optimization if we don't happen to
  298. * use a given service context, but it's main advantage is
  299. * that it allows us to change the order in which we
  300. * unmarshal them. We need to do the UnknownExceptionInfo service
  301. * context after the SendingContextRunTime service context so that we can
  302. * get the CodeBase if necessary.
  303. */
  304. private Map scMap;
  305. /**
  306. * If true, write out a special alignment service context to force the
  307. * correct alignment on re-marshalling.
  308. */
  309. private boolean addAlignmentOnWrite ;
  310. private CodeBase codeBase;
  311. private GIOPVersion giopVersion;
  312. private ORBUtilSystemException wrapper ;
  313. }