ServiceContexts.java revision 608:7e06bf1dcb09
1/* 2 * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.corba.se.spi.servicecontext; 27 28import java.lang.reflect.InvocationTargetException ; 29import java.lang.reflect.Modifier ; 30import java.lang.reflect.Field ; 31import java.lang.reflect.Constructor ; 32import java.util.*; 33 34import org.omg.CORBA.OctetSeqHelper; 35import org.omg.CORBA.SystemException; 36import org.omg.CORBA.INTERNAL; 37import org.omg.CORBA.CompletionStatus; 38import org.omg.CORBA_2_3.portable.OutputStream ; 39import org.omg.CORBA_2_3.portable.InputStream ; 40 41import com.sun.org.omg.SendingContext.CodeBase; 42 43import com.sun.corba.se.spi.ior.iiop.GIOPVersion; 44 45import com.sun.corba.se.spi.orb.ORB ; 46 47import com.sun.corba.se.spi.logging.CORBALogDomains; 48 49 50import com.sun.corba.se.spi.servicecontext.ServiceContext ; 51import com.sun.corba.se.spi.servicecontext.ServiceContextRegistry ; 52import com.sun.corba.se.spi.servicecontext.ServiceContextData ; 53import com.sun.corba.se.spi.servicecontext.UnknownServiceContext ; 54 55import com.sun.corba.se.impl.encoding.CDRInputStream; 56import com.sun.corba.se.impl.encoding.EncapsInputStream ; 57import com.sun.corba.se.impl.orbutil.ORBUtility ; 58import com.sun.corba.se.impl.util.Utility ; 59import com.sun.corba.se.impl.logging.ORBUtilSystemException ; 60 61import sun.corba.EncapsInputStreamFactory; 62 63 64public class ServiceContexts { 65 private static boolean isDebugging( OutputStream os ) 66 { 67 ORB orb = (ORB)(os.orb()) ; 68 if (orb==null) 69 return false ; 70 return orb.serviceContextDebugFlag ; 71 } 72 73 private static boolean isDebugging( InputStream is ) 74 { 75 ORB orb = (ORB)(is.orb()) ; 76 if (orb==null) 77 return false ; 78 return orb.serviceContextDebugFlag ; 79 } 80 81 private void dprint( String msg ) 82 { 83 ORBUtility.dprint( this, msg ) ; 84 } 85 86 public static void writeNullServiceContext( OutputStream os ) 87 { 88 if (isDebugging(os)) 89 ORBUtility.dprint( "ServiceContexts", "Writing null service context" ) ; 90 os.write_long( 0 ) ; 91 } 92 93 /** 94 * Given the input stream, this fills our service 95 * context map. See the definition of scMap for 96 * details. Creates a HashMap. 97 * 98 * Note that we don't actually unmarshal the 99 * bytes of the service contexts here. That is 100 * done when they are actually requested via 101 * get(int). 102 */ 103 private void createMapFromInputStream(InputStream is) 104 { 105 orb = (ORB)(is.orb()) ; 106 if (orb.serviceContextDebugFlag) 107 dprint( "Constructing ServiceContexts from input stream" ) ; 108 109 int numValid = is.read_long() ; 110 111 if (orb.serviceContextDebugFlag) 112 dprint("Number of service contexts = " + numValid); 113 114 for (int ctr = 0; ctr < numValid; ctr++) { 115 int scId = is.read_long(); 116 117 if (orb.serviceContextDebugFlag) 118 dprint("Reading service context id " + scId); 119 120 byte[] data = OctetSeqHelper.read(is); 121 122 if (orb.serviceContextDebugFlag) 123 dprint("Service context" + scId + " length: " + data.length); 124 125 scMap.put(new Integer(scId), data); 126 } 127 } 128 129 public ServiceContexts( ORB orb ) 130 { 131 this.orb = orb ; 132 wrapper = ORBUtilSystemException.get( orb, 133 CORBALogDomains.RPC_PROTOCOL ) ; 134 135 addAlignmentOnWrite = false ; 136 137 scMap = new HashMap(); 138 139 // Use the GIOP version of the ORB. Should 140 // be specified in ServiceContext. 141 // See REVISIT below concerning giopVersion. 142 giopVersion = orb.getORBData().getGIOPVersion(); 143 codeBase = null ; 144 } 145 146 /** 147 * Read the Service contexts from the input stream. 148 */ 149 public ServiceContexts(InputStream s) 150 { 151 this( (ORB)(s.orb()) ) ; 152 153 // We need to store this so that we can have access 154 // to the CodeBase for unmarshaling possible 155 // RMI-IIOP valuetype data within an encapsulation. 156 // (Known case: UnknownExceptionInfo) 157 codeBase = ((CDRInputStream)s).getCodeBase(); 158 159 createMapFromInputStream(s); 160 161 // Fix for bug 4904723 162 giopVersion = ((CDRInputStream)s).getGIOPVersion(); 163 } 164 165 /** 166 * Find the ServiceContextData for a given scId and unmarshal 167 * the bytes. 168 */ 169 private ServiceContext unmarshal(Integer scId, byte[] data) { 170 171 ServiceContextRegistry scr = orb.getServiceContextRegistry(); 172 173 ServiceContextData scd = scr.findServiceContextData(scId.intValue()); 174 ServiceContext sc = null; 175 176 if (scd == null) { 177 if (orb.serviceContextDebugFlag) { 178 dprint("Could not find ServiceContextData for " 179 + scId 180 + " using UnknownServiceContext"); 181 } 182 183 sc = new UnknownServiceContext(scId.intValue(), data); 184 185 } else { 186 187 if (orb.serviceContextDebugFlag) { 188 dprint("Found " + scd); 189 } 190 191 // REVISIT. GIOP version should be specified as 192 // part of a service context's definition, so should 193 // be accessible from ServiceContextData via 194 // its ServiceContext implementation class. 195 // 196 // Since we don't have that, yet, I'm using the GIOP 197 // version of the input stream, presuming that someone 198 // can't send a service context of a later GIOP 199 // version than its stream version. 200 // 201 // Note: As of Jan 2001, no standard OMG or Sun service contexts 202 // ship wchar data or are defined as using anything but GIOP 1.0 CDR. 203 EncapsInputStream eis 204 = EncapsInputStreamFactory.newEncapsInputStream(orb, 205 data, 206 data.length, 207 giopVersion, 208 codeBase); 209 eis.consumeEndian(); 210 211 // Now the input stream passed to a ServiceContext 212 // constructor is already the encapsulation input 213 // stream with the endianness read off, so the 214 // service context should just unmarshal its own 215 // data. 216 sc = scd.makeServiceContext(eis, giopVersion); 217 if (sc == null) 218 throw wrapper.svcctxUnmarshalError( 219 CompletionStatus.COMPLETED_MAYBE); 220 } 221 222 return sc; 223 } 224 225 public void addAlignmentPadding() 226 { 227 // Make service context 12 bytes longer by adding 228 // JAVAIDL_ALIGN_SERVICE_ID service context at end. 229 // The exact length 230 // must be >8 (minimum service context size) and 231 // =4 mod 8, so 12 is the minimum. 232 addAlignmentOnWrite = true ; 233 } 234 235 /** 236 * Hopefully unused scid: This should be changed to a proper 237 * VMCID aligned value. REVISIT! 238 */ 239 private static final int JAVAIDL_ALIGN_SERVICE_ID = 0xbe1345cd ; 240 241 /** 242 * Write the service contexts to the output stream. 243 * 244 * If they haven't been unmarshaled, we don't have to 245 * unmarshal them. 246 */ 247 public void write(OutputStream os, GIOPVersion gv) 248 { 249 if (isDebugging(os)) { 250 dprint( "Writing service contexts to output stream" ) ; 251 Utility.printStackTrace() ; 252 } 253 254 int numsc = scMap.size(); 255 256 if (addAlignmentOnWrite) { 257 if (isDebugging(os)) 258 dprint( "Adding alignment padding" ) ; 259 260 numsc++ ; 261 } 262 263 if (isDebugging(os)) 264 dprint( "Service context has " + numsc + " components" ) ; 265 266 os.write_long( numsc ) ; 267 268 writeServiceContextsInOrder(os, gv); 269 270 if (addAlignmentOnWrite) { 271 if (isDebugging(os)) 272 dprint( "Writing alignment padding" ) ; 273 274 os.write_long( JAVAIDL_ALIGN_SERVICE_ID ) ; 275 os.write_long( 4 ) ; 276 os.write_octet( (byte)0 ) ; 277 os.write_octet( (byte)0 ) ; 278 os.write_octet( (byte)0 ) ; 279 os.write_octet( (byte)0 ) ; 280 } 281 282 if (isDebugging(os)) 283 dprint( "Service context writing complete" ) ; 284 } 285 286 /** 287 * Write the service contexts in scMap in a desired order. 288 * Right now, the only special case we have is UnknownExceptionInfo, 289 * so I'm merely writing it last if present. 290 */ 291 private void writeServiceContextsInOrder(OutputStream os, GIOPVersion gv) { 292 293 // Temporarily remove this rather than check it per iteration 294 Integer ueInfoId 295 = new Integer(UEInfoServiceContext.SERVICE_CONTEXT_ID); 296 297 Object unknownExceptionInfo = scMap.remove(ueInfoId); 298 299 Iterator iter = scMap.keySet().iterator(); 300 301 while (iter.hasNext()) { 302 Integer id = (Integer)iter.next(); 303 304 writeMapEntry(os, id, scMap.get(id), gv); 305 } 306 307 // Write the UnknownExceptionInfo service context last 308 // (so it will be after the CodeBase) and restore it in 309 // the map. 310 if (unknownExceptionInfo != null) { 311 writeMapEntry(os, ueInfoId, unknownExceptionInfo, gv); 312 313 scMap.put(ueInfoId, unknownExceptionInfo); 314 } 315 } 316 317 /** 318 * Write the given entry from the scMap to the OutputStream. 319 * See note on giopVersion. The service context should 320 * know the GIOP version it is meant for. 321 */ 322 private void writeMapEntry(OutputStream os, Integer id, Object scObj, GIOPVersion gv) { 323 324 // If it's still in byte[] form, we don't need to 325 // unmarshal it here, just copy the bytes into 326 // the new stream. 327 328 if (scObj instanceof byte[]) { 329 if (isDebugging(os)) 330 dprint( "Writing service context bytes for id " + id); 331 332 OctetSeqHelper.write(os, (byte[])scObj); 333 334 } else { 335 336 // We actually unmarshaled it into a ServiceContext 337 // at some point. 338 ServiceContext sc = (ServiceContext)scObj; 339 340 if (isDebugging(os)) 341 dprint( "Writing service context " + sc ) ; 342 343 sc.write(os, gv); 344 } 345 } 346 347 /** Add a service context to the stream, if there is not already 348 * a service context in this object with the same id as sc. 349 */ 350 public void put( ServiceContext sc ) 351 { 352 Integer id = new Integer(sc.getId()); 353 scMap.put(id, sc); 354 } 355 356 public void delete( int scId ) { 357 this.delete(new Integer(scId)); 358 } 359 360 public void delete(Integer id) 361 { 362 scMap.remove(id) ; 363 } 364 365 public ServiceContext get(int scId) { 366 return this.get(new Integer(scId)); 367 } 368 369 public ServiceContext get(Integer id) 370 { 371 Object result = scMap.get(id); 372 if (result == null) 373 return null ; 374 375 // Lazy unmarshaling on first use. 376 if (result instanceof byte[]) { 377 378 ServiceContext sc = unmarshal(id, (byte[])result); 379 380 scMap.put(id, sc); 381 382 return sc; 383 } else { 384 return (ServiceContext)result; 385 } 386 } 387 388 private ORB orb ; 389 390 /** 391 * Map of all ServiceContext objects in this container. 392 * 393 * Keys are java.lang.Integers for service context IDs. 394 * Values are either instances of ServiceContext or the 395 * unmarshaled byte arrays (unmarshaled on first use). 396 * 397 * This provides a mild optimization if we don't happen to 398 * use a given service context, but it's main advantage is 399 * that it allows us to change the order in which we 400 * unmarshal them. We need to do the UnknownExceptionInfo service 401 * context after the SendingContextRunTime service context so that we can 402 * get the CodeBase if necessary. 403 */ 404 private Map scMap; 405 406 /** 407 * If true, write out a special alignment service context to force the 408 * correct alignment on re-marshalling. 409 */ 410 private boolean addAlignmentOnWrite ; 411 412 private CodeBase codeBase; 413 private GIOPVersion giopVersion; 414 private ORBUtilSystemException wrapper ; 415} 416