- /*
- * @(#)ServiceContexts.java 1.24 04/06/21
- *
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
- * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
-
- package com.sun.corba.se.spi.servicecontext;
-
- import java.lang.reflect.InvocationTargetException ;
- import java.lang.reflect.Modifier ;
- import java.lang.reflect.Field ;
- import java.lang.reflect.Constructor ;
- import java.util.*;
-
- import org.omg.CORBA.OctetSeqHelper;
- import org.omg.CORBA.SystemException;
- import org.omg.CORBA.INTERNAL;
- import org.omg.CORBA.CompletionStatus;
- import org.omg.CORBA_2_3.portable.OutputStream ;
- import org.omg.CORBA_2_3.portable.InputStream ;
-
- import com.sun.org.omg.SendingContext.CodeBase;
-
- import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
-
- import com.sun.corba.se.spi.orb.ORB ;
-
- import com.sun.corba.se.spi.logging.CORBALogDomains;
-
-
- import com.sun.corba.se.spi.servicecontext.ServiceContext ;
- import com.sun.corba.se.spi.servicecontext.ServiceContextRegistry ;
- import com.sun.corba.se.spi.servicecontext.ServiceContextData ;
- import com.sun.corba.se.spi.servicecontext.UnknownServiceContext ;
-
- import com.sun.corba.se.impl.encoding.CDRInputStream;
- import com.sun.corba.se.impl.encoding.EncapsInputStream ;
- import com.sun.corba.se.impl.orbutil.ORBUtility ;
- import com.sun.corba.se.impl.util.Utility ;
- import com.sun.corba.se.impl.logging.ORBUtilSystemException ;
-
- public class ServiceContexts {
- private static boolean isDebugging( OutputStream os )
- {
- ORB orb = (ORB)(os.orb()) ;
- if (orb==null)
- return false ;
- return orb.serviceContextDebugFlag ;
- }
-
- private static boolean isDebugging( InputStream is )
- {
- ORB orb = (ORB)(is.orb()) ;
- if (orb==null)
- return false ;
- return orb.serviceContextDebugFlag ;
- }
-
- private void dprint( String msg )
- {
- ORBUtility.dprint( this, msg ) ;
- }
-
- public static void writeNullServiceContext( OutputStream os )
- {
- if (isDebugging(os))
- ORBUtility.dprint( "ServiceContexts", "Writing null service context" ) ;
- os.write_long( 0 ) ;
- }
-
- /**
- * Given the input stream, this fills our service
- * context map. See the definition of scMap for
- * details. Creates a HashMap.
- *
- * Note that we don't actually unmarshal the
- * bytes of the service contexts here. That is
- * done when they are actually requested via
- * get(int).
- */
- private void createMapFromInputStream(InputStream is)
- {
- orb = (ORB)(is.orb()) ;
- if (orb.serviceContextDebugFlag)
- dprint( "Constructing ServiceContexts from input stream" ) ;
-
- int numValid = is.read_long() ;
-
- if (orb.serviceContextDebugFlag)
- dprint("Number of service contexts = " + numValid);
-
- for (int ctr = 0; ctr < numValid; ctr++) {
- int scId = is.read_long();
-
- if (orb.serviceContextDebugFlag)
- dprint("Reading service context id " + scId);
-
- byte[] data = OctetSeqHelper.read(is);
-
- if (orb.serviceContextDebugFlag)
- dprint("Service context" + scId + " length: " + data.length);
-
- scMap.put(new Integer(scId), data);
- }
- }
-
- public ServiceContexts( ORB orb )
- {
- this.orb = orb ;
- wrapper = ORBUtilSystemException.get( orb,
- CORBALogDomains.RPC_PROTOCOL ) ;
-
- addAlignmentOnWrite = false ;
-
- scMap = new HashMap();
-
- // Use the GIOP version of the ORB. Should
- // be specified in ServiceContext.
- // See REVISIT below concerning giopVersion.
- giopVersion = orb.getORBData().getGIOPVersion();
- codeBase = null ;
- }
-
- /**
- * Read the Service contexts from the input stream.
- */
- public ServiceContexts(InputStream s)
- {
- this( (ORB)(s.orb()) ) ;
-
- // We need to store this so that we can have access
- // to the CodeBase for unmarshaling possible
- // RMI-IIOP valuetype data within an encapsulation.
- // (Known case: UnknownExceptionInfo)
- codeBase = ((CDRInputStream)s).getCodeBase();
-
- createMapFromInputStream(s);
-
- // Fix for bug 4904723
- giopVersion = ((CDRInputStream)s).getGIOPVersion();
- }
-
- /**
- * Find the ServiceContextData for a given scId and unmarshal
- * the bytes.
- */
- private ServiceContext unmarshal(Integer scId, byte[] data) {
-
- ServiceContextRegistry scr = orb.getServiceContextRegistry();
-
- ServiceContextData scd = scr.findServiceContextData(scId.intValue());
- ServiceContext sc = null;
-
- if (scd == null) {
- if (orb.serviceContextDebugFlag) {
- dprint("Could not find ServiceContextData for "
- + scId
- + " using UnknownServiceContext");
- }
-
- sc = new UnknownServiceContext(scId.intValue(), data);
-
- } else {
-
- if (orb.serviceContextDebugFlag) {
- dprint("Found " + scd);
- }
-
- // REVISIT. GIOP version should be specified as
- // part of a service context's definition, so should
- // be accessible from ServiceContextData via
- // its ServiceContext implementation class.
- //
- // Since we don't have that, yet, I'm using the GIOP
- // version of the input stream, presuming that someone
- // can't send a service context of a later GIOP
- // version than its stream version.
- //
- // Note: As of Jan 2001, no standard OMG or Sun service contexts
- // ship wchar data or are defined as using anything but GIOP 1.0 CDR.
- EncapsInputStream eis
- = new EncapsInputStream(orb,
- data,
- data.length,
- giopVersion,
- codeBase);
- eis.consumeEndian();
-
- // Now the input stream passed to a ServiceContext
- // constructor is already the encapsulation input
- // stream with the endianness read off, so the
- // service context should just unmarshal its own
- // data.
- sc = scd.makeServiceContext(eis, giopVersion);
- if (sc == null)
- throw wrapper.svcctxUnmarshalError(
- CompletionStatus.COMPLETED_MAYBE);
- }
-
- return sc;
- }
-
- public void addAlignmentPadding()
- {
- // Make service context 12 bytes longer by adding
- // JAVAIDL_ALIGN_SERVICE_ID service context at end.
- // The exact length
- // must be >8 (minimum service context size) and
- // =4 mod 8, so 12 is the minimum.
- addAlignmentOnWrite = true ;
- }
-
- /**
- * Hopefully unused scid: This should be changed to a proper
- * VMCID aligned value. REVISIT!
- */
- private static final int JAVAIDL_ALIGN_SERVICE_ID = 0xbe1345cd ;
-
- /**
- * Write the service contexts to the output stream.
- *
- * If they haven't been unmarshaled, we don't have to
- * unmarshal them.
- */
- public void write(OutputStream os, GIOPVersion gv)
- {
- if (isDebugging(os)) {
- dprint( "Writing service contexts to output stream" ) ;
- Utility.printStackTrace() ;
- }
-
- int numsc = scMap.size();
-
- if (addAlignmentOnWrite) {
- if (isDebugging(os))
- dprint( "Adding alignment padding" ) ;
-
- numsc++ ;
- }
-
- if (isDebugging(os))
- dprint( "Service context has " + numsc + " components" ) ;
-
- os.write_long( numsc ) ;
-
- writeServiceContextsInOrder(os, gv);
-
- if (addAlignmentOnWrite) {
- if (isDebugging(os))
- dprint( "Writing alignment padding" ) ;
-
- os.write_long( JAVAIDL_ALIGN_SERVICE_ID ) ;
- os.write_long( 4 ) ;
- os.write_octet( (byte)0 ) ;
- os.write_octet( (byte)0 ) ;
- os.write_octet( (byte)0 ) ;
- os.write_octet( (byte)0 ) ;
- }
-
- if (isDebugging(os))
- dprint( "Service context writing complete" ) ;
- }
-
- /**
- * Write the service contexts in scMap in a desired order.
- * Right now, the only special case we have is UnknownExceptionInfo,
- * so I'm merely writing it last if present.
- */
- private void writeServiceContextsInOrder(OutputStream os, GIOPVersion gv) {
-
- // Temporarily remove this rather than check it per iteration
- Integer ueInfoId
- = new Integer(UEInfoServiceContext.SERVICE_CONTEXT_ID);
-
- Object unknownExceptionInfo = scMap.remove(ueInfoId);
-
- Iterator iter = scMap.keySet().iterator();
-
- while (iter.hasNext()) {
- Integer id = (Integer)iter.next();
-
- writeMapEntry(os, id, scMap.get(id), gv);
- }
-
- // Write the UnknownExceptionInfo service context last
- // (so it will be after the CodeBase) and restore it in
- // the map.
- if (unknownExceptionInfo != null) {
- writeMapEntry(os, ueInfoId, unknownExceptionInfo, gv);
-
- scMap.put(ueInfoId, unknownExceptionInfo);
- }
- }
-
- /**
- * Write the given entry from the scMap to the OutputStream.
- * See note on giopVersion. The service context should
- * know the GIOP version it is meant for.
- */
- private void writeMapEntry(OutputStream os, Integer id, Object scObj, GIOPVersion gv) {
-
- // If it's still in byte[] form, we don't need to
- // unmarshal it here, just copy the bytes into
- // the new stream.
-
- if (scObj instanceof byte[]) {
- if (isDebugging(os))
- dprint( "Writing service context bytes for id " + id);
-
- OctetSeqHelper.write(os, (byte[])scObj);
-
- } else {
-
- // We actually unmarshaled it into a ServiceContext
- // at some point.
- ServiceContext sc = (ServiceContext)scObj;
-
- if (isDebugging(os))
- dprint( "Writing service context " + sc ) ;
-
- sc.write(os, gv);
- }
- }
-
- /** Add a service context to the stream, if there is not already
- * a service context in this object with the same id as sc.
- */
- public void put( ServiceContext sc )
- {
- Integer id = new Integer(sc.getId());
- scMap.put(id, sc);
- }
-
- public void delete( int scId ) {
- this.delete(new Integer(scId));
- }
-
- public void delete(Integer id)
- {
- scMap.remove(id) ;
- }
-
- public ServiceContext get(int scId) {
- return this.get(new Integer(scId));
- }
-
- public ServiceContext get(Integer id)
- {
- Object result = scMap.get(id);
- if (result == null)
- return null ;
-
- // Lazy unmarshaling on first use.
- if (result instanceof byte[]) {
-
- ServiceContext sc = unmarshal(id, (byte[])result);
-
- scMap.put(id, sc);
-
- return sc;
- } else {
- return (ServiceContext)result;
- }
- }
-
- private ORB orb ;
-
- /**
- * Map of all ServiceContext objects in this container.
- *
- * Keys are java.lang.Integers for service context IDs.
- * Values are either instances of ServiceContext or the
- * unmarshaled byte arrays (unmarshaled on first use).
- *
- * This provides a mild optimization if we don't happen to
- * use a given service context, but it's main advantage is
- * that it allows us to change the order in which we
- * unmarshal them. We need to do the UnknownExceptionInfo service
- * context after the SendingContextRunTime service context so that we can
- * get the CodeBase if necessary.
- */
- private Map scMap;
-
- /**
- * If true, write out a special alignment service context to force the
- * correct alignment on re-marshalling.
- */
- private boolean addAlignmentOnWrite ;
-
- private CodeBase codeBase;
- private GIOPVersion giopVersion;
- private ORBUtilSystemException wrapper ;
- }