1. /*
  2. * @(#)CorbalocURL.java 1.7 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.corba.se.impl.naming.namingutil;
  8. import java.util.*;
  9. import com.sun.corba.se.spi.logging.CORBALogDomains ;
  10. import com.sun.corba.se.impl.logging.NamingSystemException ;
  11. /**
  12. * The corbaloc: URL definitions from the -ORBInitDef and -ORBDefaultInitDef's
  13. * will be parsed and converted to this object. This object is capable of
  14. * storing multiple Host profiles as defined in the CorbaLoc grammer.
  15. *
  16. * @author Hemanth
  17. */
  18. public class CorbalocURL extends INSURLBase
  19. {
  20. static NamingSystemException wrapper = NamingSystemException.get(
  21. CORBALogDomains.NAMING_READ ) ;
  22. /**
  23. * This constructor parses the URL and initializes all the variables. Once
  24. * the URL Object is constructed it is immutable. URL parameter is a
  25. * corbaloc: URL string with 'corbaloc:' prefix stripped.
  26. */
  27. public CorbalocURL( String aURL ) {
  28. String url = aURL;
  29. if( url != null ) {
  30. try {
  31. // First Clean the URL Escapes if there are any
  32. url = Utility.cleanEscapes( url );
  33. } catch( Exception e ) {
  34. // There is something wrong with the URL escapes used
  35. // so throw an exception
  36. badAddress( e );
  37. }
  38. int endIndex = url.indexOf( '/' );
  39. if( endIndex == -1 ) {
  40. // If there is no '/' then the endIndex is at the end of the URL
  41. endIndex = url.length();
  42. }
  43. // _REVISIT_: Add a testcase to check 'corbaloc:/'
  44. if( endIndex == 0 ) {
  45. // The url starts with a '/', it's an error
  46. badAddress( null );
  47. }
  48. // Anything between corbaloc: and / is the host,port information
  49. // of the server where the Service Object is located
  50. StringTokenizer endpoints = new StringTokenizer(
  51. url.substring( 0, endIndex ), "," );
  52. // NOTE:
  53. // There should be atleast one token, because there are checks
  54. // to make sure that there is host information before the
  55. // delimiter '/'. So no need to explicitly check for number of
  56. // tokens != 0
  57. while( endpoints.hasMoreTokens( ) ) {
  58. String endpointInfo = endpoints.nextToken();
  59. IIOPEndpointInfo iiopEndpointInfo = null;
  60. if( endpointInfo.startsWith( "iiop:" ) ) {
  61. iiopEndpointInfo = handleIIOPColon( endpointInfo );
  62. } else if( endpointInfo.startsWith( "rir:" ) ) {
  63. handleRIRColon( endpointInfo );
  64. rirFlag = true;
  65. } else if( endpointInfo.startsWith( ":" ) ) {
  66. iiopEndpointInfo = handleColon( endpointInfo );
  67. } else {
  68. // Right now we are not allowing any other protocol
  69. // other than iiop:, rir: so raise exception indicating
  70. // that the URL is malformed
  71. badAddress( null );
  72. }
  73. if ( rirFlag == false ) {
  74. // Add the Host information if RIR flag is set,
  75. // If RIR is set then it means use the internal Boot
  76. // Strap protocol for Key String resolution
  77. if( theEndpointInfo == null ) {
  78. theEndpointInfo = new java.util.ArrayList( );
  79. }
  80. theEndpointInfo.add( iiopEndpointInfo );
  81. }
  82. }
  83. // If there is something after corbaloc:endpointInfo/
  84. // then that is the keyString
  85. if( url.length() > (endIndex + 1) ) {
  86. theKeyString = url.substring( endIndex + 1 );
  87. }
  88. }
  89. }
  90. /**
  91. * A Utility method to throw BAD_PARAM exception to signal malformed
  92. * INS URL.
  93. */
  94. private void badAddress( java.lang.Throwable e )
  95. {
  96. throw wrapper.insBadAddress( e ) ;
  97. }
  98. /**
  99. * If there is 'iiop:' token in the URL, this method will parses
  100. * and validates that host and port information.
  101. */
  102. private IIOPEndpointInfo handleIIOPColon( String iiopInfo )
  103. {
  104. // Check the iiop syntax
  105. iiopInfo = iiopInfo.substring( NamingConstants.IIOP_LENGTH );
  106. return handleColon( iiopInfo );
  107. }
  108. /**
  109. * This is to handle the case of host information with no 'iiop:' prefix.
  110. * instead if ':' is specified then iiop is assumed.
  111. */
  112. private IIOPEndpointInfo handleColon( String iiopInfo ) {
  113. // String after ":"
  114. iiopInfo = iiopInfo.substring( 1 );
  115. String hostandport = iiopInfo;
  116. // The format can be 1.2@<host>:<port>
  117. StringTokenizer tokenizer = new StringTokenizer( iiopInfo, "@" );
  118. IIOPEndpointInfo iiopEndpointInfo = new IIOPEndpointInfo( );
  119. int tokenCount = tokenizer.countTokens( );
  120. // There can be 1 or 2 tokens with '@' as the delimiter
  121. // - if there is only 1 token then there is no GIOP version
  122. // information. A Default GIOP version of 1.2 is used.
  123. // - if there are 2 tokens then there is GIOP version is specified
  124. // - if there are no tokens or more than 2 tokens, then that's an
  125. // error
  126. if( ( tokenCount == 0 )
  127. ||( tokenCount > 2 ))
  128. {
  129. badAddress( null );
  130. }
  131. if( tokenCount == 2 ) {
  132. // There is VersionInformation after iiop:
  133. String version = tokenizer.nextToken( );
  134. int dot = version.indexOf('.');
  135. // There is a version without ., which means
  136. // Malformed list
  137. if (dot == -1) {
  138. badAddress( null );
  139. }
  140. try {
  141. iiopEndpointInfo.setVersion(
  142. Integer.parseInt( version.substring( 0, dot )),
  143. Integer.parseInt( version.substring(dot+1)) );
  144. hostandport = tokenizer.nextToken( );
  145. } catch( Throwable e ) {
  146. badAddress( e );
  147. }
  148. }
  149. try {
  150. // A Hack to differentiate IPV6 address
  151. // from IPV4 address, Current Resolution
  152. // is to use [ ] to differentiate ipv6 host
  153. int squareBracketBeginIndex = hostandport.indexOf ( '[' );
  154. if( squareBracketBeginIndex != -1 ) {
  155. // ipv6Host should be enclosed in
  156. // [ ], if not it will result in a
  157. // BAD_PARAM exception
  158. String ipv6Port = getIPV6Port( hostandport );
  159. if( ipv6Port != null ) {
  160. iiopEndpointInfo.setPort( Integer.parseInt( ipv6Port ));
  161. }
  162. iiopEndpointInfo.setHost( getIPV6Host( hostandport ));
  163. return iiopEndpointInfo;
  164. }
  165. tokenizer = new StringTokenizer( hostandport, ":" );
  166. // There are three possible cases here
  167. // 1. Host and Port is explicitly specified by using ":" as a
  168. // a separator
  169. // 2. Only Host is specified without the port
  170. // 3. HostAndPort info is null
  171. if( tokenizer.countTokens( ) == 2 ) {
  172. // Case 1: There is Host and Port Info
  173. iiopEndpointInfo.setHost( tokenizer.nextToken( ) );
  174. iiopEndpointInfo.setPort( Integer.parseInt(
  175. tokenizer.nextToken( )));
  176. } else {
  177. if( ( hostandport != null )
  178. &&( hostandport.length() != 0 ) )
  179. {
  180. // Case 2: Only Host is specified. iiopEndpointInfo is
  181. // initialized to use the default INS port, if no port is
  182. // specified
  183. iiopEndpointInfo.setHost( hostandport );
  184. }
  185. // Case 3: If no Host and Port info is provided then we use the
  186. // the default LocalHost and INSPort. iiopEndpointInfo is
  187. // already initialized with this info.
  188. }
  189. } catch( Throwable e ) {
  190. // Any kind of Exception is bad here.
  191. // Possible causes: A Number Format exception because port info is
  192. // malformed
  193. badAddress( e );
  194. }
  195. Utility.validateGIOPVersion( iiopEndpointInfo );
  196. return iiopEndpointInfo;
  197. }
  198. /**
  199. * Validate 'rir:' case.
  200. */
  201. private void handleRIRColon( String rirInfo )
  202. {
  203. if( rirInfo.length() != NamingConstants.RIRCOLON_LENGTH ) {
  204. badAddress( null );
  205. }
  206. }
  207. /**
  208. * Returns an IPV6 Port that is after [<ipv6>]:. There is no validation
  209. * done here, if it is an incorrect port then the request through
  210. * this URL results in a COMM_FAILURE, otherwise malformed list will
  211. * result in BAD_PARAM exception thrown in checkcorbalocGrammer.
  212. */
  213. private String getIPV6Port( String endpointInfo )
  214. {
  215. int squareBracketEndIndex = endpointInfo.indexOf ( ']' );
  216. // If there is port information, then it has to be after ] bracket
  217. // indexOf returns the count from the index of zero as the base, so
  218. // equality check requires squareBracketEndIndex + 1.
  219. if( (squareBracketEndIndex + 1) != (endpointInfo.length( )) ) {
  220. if( endpointInfo.charAt( squareBracketEndIndex + 1 ) != ':' ) {
  221. throw new RuntimeException(
  222. "Host and Port is not separated by ':'" );
  223. }
  224. // PortInformation should be after ']:' delimiter
  225. // If there is an exception then it will be caught in
  226. // checkcorbaGrammer method and rethrown as BAD_PARAM
  227. return endpointInfo.substring( squareBracketEndIndex + 2 );
  228. }
  229. return null;
  230. }
  231. /**
  232. * Returns an IPV6 Host that is inside [ ] tokens. There is no validation
  233. * done here, if it is an incorrect IPV6 address then the request through
  234. * this URL results in a COMM_FAILURE, otherwise malformed list will
  235. * result in BAD_PARAM exception thrown in checkcorbalocGrammer.
  236. */
  237. private String getIPV6Host( String endpointInfo ) {
  238. // ipv6Host should be enclosed in
  239. // [ ], if not it will result in a
  240. // BAD_PARAM exception
  241. int squareBracketEndIndex = endpointInfo.indexOf ( ']' );
  242. // get the host between [ ]
  243. String ipv6Host = endpointInfo.substring( 1, squareBracketEndIndex );
  244. return ipv6Host;
  245. }
  246. /**
  247. * Will be true only in CorbanameURL class.
  248. */
  249. public boolean isCorbanameURL( ) {
  250. return false;
  251. }
  252. }