/*
 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

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 ;

import sun.corba.EncapsInputStreamFactory;


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).
/** * 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.
/** * 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.
/** * 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 = EncapsInputStreamFactory.newEncapsInputStream(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!
/** * 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.
/** * 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.
/** * 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.
/** * 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.
/** 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.
/** * 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.
/** * 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 ; }