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