blob: ea4569b1a14031b6cda3c3fe4ce5f0625866d1df [file] [log] [blame]
/*
* 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).
*/
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
= 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!
*/
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 ;
}