/*
* Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package com.sun.corba.se.impl.resolver;
import java.util.List ;
import java.util.Map ;
import java.util.Comparator ;
import java.util.Iterator ;
import java.util.HashMap ;
import java.util.ArrayList ;
import java.util.Collections ;
import org.omg.CosNaming.NamingContextExt ;
import org.omg.CosNaming.NamingContextExtHelper ;
import sun.corba.EncapsInputStreamFactory;
import com.sun.corba.se.spi.ior.IOR;
import com.sun.corba.se.spi.ior.IORTemplate;
import com.sun.corba.se.spi.ior.ObjectKey;
import com.sun.corba.se.spi.ior.IORFactories;
import com.sun.corba.se.spi.ior.ObjectKeyFactory ;
import com.sun.corba.se.spi.ior.iiop.IIOPAddress;
import com.sun.corba.se.spi.ior.iiop.IIOPProfile ;
import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
import com.sun.corba.se.spi.ior.iiop.IIOPFactories ;
import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent;
import com.sun.corba.se.spi.logging.CORBALogDomains ;
import com.sun.corba.se.spi.orb.Operation;
import com.sun.corba.se.spi.orb.ORB;
import com.sun.corba.se.spi.resolver.Resolver;
import com.sun.corba.se.impl.encoding.EncapsInputStream;
import com.sun.corba.se.impl.logging.ORBUtilSystemException;
import com.sun.corba.se.impl.logging.OMGSystemException;
import com.sun.corba.se.impl.naming.namingutil.INSURLHandler;
import com.sun.corba.se.impl.naming.namingutil.IIOPEndpointInfo;
import com.sun.corba.se.impl.naming.namingutil.INSURL;
import com.sun.corba.se.impl.naming.namingutil.CorbalocURL;
import com.sun.corba.se.impl.naming.namingutil.CorbanameURL;
import com.sun.corba.se.impl.orbutil.ORBConstants;
import com.sun.corba.se.impl.orbutil.ORBUtility;
/**
* This class provides an Operation that converts from CORBA INS URL strings into
* CORBA object references. It will eventually become extensible, but for now it
* simply encapsulates the existing implementation. Once the full extensibility
* is in place, we want this operation to convert string to INSURL, which has mainly
* a public resolver method that returns an object reference.
*
* @author Hemanth
* @author Ken
*/
public class INSURLOperationImpl implements Operation
{
ORB orb;
ORBUtilSystemException wrapper ;
OMGSystemException omgWrapper ;
Resolver bootstrapResolver ;
// Root Naming Context for default resolution of names.
private NamingContextExt rootNamingContextExt;
private Object rootContextCacheLock = new Object() ;
// The URLHandler to parse INS URL's
private INSURLHandler insURLHandler = INSURLHandler.getINSURLHandler() ;
public INSURLOperationImpl( ORB orb, Resolver bootstrapResolver )
{
this.orb = orb ;
wrapper = ORBUtilSystemException.get( orb,
CORBALogDomains.ORB_RESOLVER ) ;
omgWrapper = OMGSystemException.get( orb,
CORBALogDomains.ORB_RESOLVER ) ;
this.bootstrapResolver = bootstrapResolver ;
}
private static final int NIBBLES_PER_BYTE = 2 ;
private static final int UN_SHIFT = 4 ; // "UPPER NIBBLE" shift factor for <<
/** This static method takes a Stringified IOR and converts it into IOR object.
* It is the caller's responsibility to only pass strings that start with "IOR:".
*/
private org.omg.CORBA.Object getIORFromString( String str )
{
// Length must be even for str to be valid
if ( (str.length() & 1) == 1 )
throw wrapper.badStringifiedIorLen() ;
byte[] buf = new byte[(str.length() - ORBConstants.STRINGIFY_PREFIX.length()) / NIBBLES_PER_BYTE];
for (int i=ORBConstants.STRINGIFY_PREFIX.length(), j=0; i < str.length(); i +=NIBBLES_PER_BYTE, j++) {
buf[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << UN_SHIFT) & 0xF0);
buf[j] |= (byte)(ORBUtility.hexOf(str.charAt(i+1)) & 0x0F);
}
EncapsInputStream s = EncapsInputStreamFactory.newEncapsInputStream(orb, buf, buf.length,
orb.getORBData().getGIOPVersion());
s.consumeEndian();
return s.read_Object() ;
}
public Object operate( Object arg )
{
if (arg instanceof String) {
String str = (String)arg ;
if (str.startsWith( ORBConstants.STRINGIFY_PREFIX ))
// XXX handle this as just another URL scheme
return getIORFromString( str ) ;
else {
INSURL insURL = insURLHandler.parseURL( str ) ;
if (insURL == null)
throw omgWrapper.soBadSchemeName() ;
return resolveINSURL( insURL ) ;
}
}
throw wrapper.stringExpected() ;
}
private org.omg.CORBA.Object resolveINSURL( INSURL theURLObject ) {
// XXX resolve should be a method on INSURL
if( theURLObject.isCorbanameURL() ) {
return resolveCorbaname( (CorbanameURL)theURLObject );
} else {
return resolveCorbaloc( (CorbalocURL)theURLObject );
}
}
/**
* resolves a corbaloc: url that is encapsulated in a CorbalocURL object.
*
* @return the CORBA.Object if resolution is successful
*/
private org.omg.CORBA.Object resolveCorbaloc(
CorbalocURL theCorbaLocObject )
{
org.omg.CORBA.Object result = null;
// If RIR flag is true use the Bootstrap protocol
if( theCorbaLocObject.getRIRFlag( ) ) {
result = bootstrapResolver.resolve(theCorbaLocObject.getKeyString());
} else {
result = getIORUsingCorbaloc( theCorbaLocObject );
}
return result;
}
/**
* resolves a corbaname: url that is encapsulated in a CorbanameURL object.
*
* @return the CORBA.Object if resolution is successful
*/
private org.omg.CORBA.Object resolveCorbaname( CorbanameURL theCorbaName ) {
org.omg.CORBA.Object result = null;
try {
NamingContextExt theNamingContext = null;
if( theCorbaName.getRIRFlag( ) ) {
// Case 1 of corbaname: rir#
theNamingContext = getDefaultRootNamingContext( );
} else {
// Case 2 of corbaname: ::hostname#
org.omg.CORBA.Object corbalocResult =
getIORUsingCorbaloc( theCorbaName );
if( corbalocResult == null ) {
return null;
}
theNamingContext =
NamingContextExtHelper.narrow( corbalocResult );
}
String StringifiedName = theCorbaName.getStringifiedName( );
if( StringifiedName == null ) {
// This means return the Root Naming context
return theNamingContext;
} else {
return theNamingContext.resolve_str( StringifiedName );
}
} catch( Exception e ) {
clearRootNamingContextCache( );
return null;
}
}
/**
* This is an internal method to get the IOR from the CorbalocURL object.
*
* @return the CORBA.Object if resolution is successful
*/
private org.omg.CORBA.Object getIORUsingCorbaloc( INSURL corbalocObject )
{
Map profileMap = new HashMap();
List profileList1_0 = new ArrayList();
// corbalocObject cannot be null, because it's validated during
// parsing. So no null check is required.
java.util.List theEndpointInfo = corbalocObject.getEndpointInfo();
String theKeyString = corbalocObject.getKeyString();
// If there is no KeyString then it's invalid
if( theKeyString == null ) {
return null;
}
ObjectKey key = orb.getObjectKeyFactory().create(
theKeyString.getBytes() );
IORTemplate iortemp = IORFactories.makeIORTemplate( key.getTemplate() );
java.util.Iterator iterator = theEndpointInfo.iterator( );
while( iterator.hasNext( ) ) {
IIOPEndpointInfo element =
(IIOPEndpointInfo) iterator.next( );
IIOPAddress addr = IIOPFactories.makeIIOPAddress( orb, element.getHost(),
element.getPort() );
GIOPVersion giopVersion = GIOPVersion.getInstance( (byte)element.getMajor(),
(byte)element.getMinor());
IIOPProfileTemplate profileTemplate = null;
if (giopVersion.equals(GIOPVersion.V1_0)) {
profileTemplate = IIOPFactories.makeIIOPProfileTemplate(
orb, giopVersion, addr);
profileList1_0.add(profileTemplate);
} else {
if (profileMap.get(giopVersion) == null) {
profileTemplate = IIOPFactories.makeIIOPProfileTemplate(
orb, giopVersion, addr);
profileMap.put(giopVersion, profileTemplate);
} else {
profileTemplate = (IIOPProfileTemplate)profileMap.get(giopVersion);
AlternateIIOPAddressComponent iiopAddressComponent =
IIOPFactories.makeAlternateIIOPAddressComponent(addr);
profileTemplate.add(iiopAddressComponent);
}
}
}
GIOPVersion giopVersion = orb.getORBData().getGIOPVersion();
IIOPProfileTemplate pTemplate = (IIOPProfileTemplate)profileMap.get(giopVersion);
if (pTemplate != null) {
iortemp.add(pTemplate); // Add profile for GIOP version used by this ORB
profileMap.remove(giopVersion); // Now remove this value from the map
}
// Create a comparator that can sort in decending order (1.2, 1.1, ...)
Comparator comp = new Comparator() {
public int compare(Object o1, Object o2) {
GIOPVersion gv1 = (GIOPVersion)o1;
GIOPVersion gv2 = (GIOPVersion)o2;
return (gv1.lessThan(gv2) ? 1 : (gv1.equals(gv2) ? 0 : -1));
};
};
// Now sort using the above comparator
List list = new ArrayList(profileMap.keySet());
Collections.sort(list, comp);
// Add the profiles in the sorted order
Iterator iter = list.iterator();
while (iter.hasNext()) {
IIOPProfileTemplate pt = (IIOPProfileTemplate)profileMap.get(iter.next());
iortemp.add(pt);
}
// Finally add the 1.0 profiles
iortemp.addAll(profileList1_0);
IOR ior = iortemp.makeIOR( orb, "", key.getId() ) ;
return ORBUtility.makeObjectReference( ior ) ;
}
/**
* This is required for corbaname: resolution. Currently we
* are not caching RootNamingContext as the reference to rootNamingContext
* may not be Persistent in all the implementations.
* _REVISIT_ to clear the rootNamingContext in case of COMM_FAILURE.
*
* @return the org.omg.COSNaming.NamingContextExt if resolution is
* successful
*
*/
private NamingContextExt getDefaultRootNamingContext( ) {
synchronized( rootContextCacheLock ) {
if( rootNamingContextExt == null ) {
try {
rootNamingContextExt =
NamingContextExtHelper.narrow(
orb.getLocalResolver().resolve( "NameService" ) );
} catch( Exception e ) {
rootNamingContextExt = null;
}
}
}
return rootNamingContextExt;
}
/**
* A utility method to clear the RootNamingContext, if there is an
* exception in resolving CosNaming:Name from the RootNamingContext,
*/
private void clearRootNamingContextCache( ) {
synchronized( rootContextCacheLock ) {
rootNamingContextExt = null;
}
}
}