InterOperableNamingImpl.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 2000, 2003, 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.impl.naming.cosnaming;
27
28import org.omg.CosNaming.NamingContextExtPackage.*;
29import java.io.StringWriter;
30
31// Import general CORBA classes
32import org.omg.CORBA.SystemException;
33import org.omg.CORBA.Object;
34
35// Import org.omg.CosNaming types
36import org.omg.CosNaming.NameComponent;
37import org.omg.CosNaming.NamingContext;
38
39
40/**
41 * Class InteroperableNamingImpl implements the methods defined
42 * for NamingContextExt which is part of Interoperable Naming
43 * Service specifications. This class is added for doing more
44 * of Parsing and Building of Stringified names according to INS
45 * Spec.
46 */
47public class InterOperableNamingImpl
48{
49   /**
50     * Method which stringifies the Name Components given as the input
51     * parameter.
52     *
53     * @param n Array of Name Components (Simple or Compound Names)
54     * @return string which is the stringified reference.
55     */
56    public String convertToString( org.omg.CosNaming.NameComponent[]
57                                   theNameComponents )
58    {
59        String theConvertedString =
60            convertNameComponentToString( theNameComponents[0] );
61        String temp;
62        for( int i = 1; i < theNameComponents.length; i++ ) {
63            temp = convertNameComponentToString( theNameComponents[i] );
64            if( temp != null ) {
65                 theConvertedString =
66                 theConvertedString + "/" +  convertNameComponentToString(
67                     theNameComponents[i] );
68            }
69        }
70        return theConvertedString;
71    }
72
73   /** This method converts a single Namecomponent to String, By adding Escapes
74    *  If neccessary.
75    */
76    private String convertNameComponentToString(
77        org.omg.CosNaming.NameComponent theNameComponent )
78    {
79        if( ( ( theNameComponent.id == null )
80            ||( theNameComponent.id.length() == 0 ) )
81          &&( ( theNameComponent.kind == null )
82            ||( theNameComponent.kind.length() == 0 ) ) )
83        {
84            return ".";
85        }
86        else if( ( theNameComponent.id == null )
87               ||( theNameComponent.id.length() == 0 ) )
88        {
89            String kind = addEscape( theNameComponent.kind );
90            return "." + kind;
91        }
92        else if( ( theNameComponent.kind == null )
93               ||( theNameComponent.kind.length() == 0 ) )
94        {
95            String id = addEscape( theNameComponent.id );
96            return id;
97        }
98        else {
99            String id = addEscape( theNameComponent.id );
100            String kind = addEscape( theNameComponent.kind );
101            return (id + "." +  kind);
102        }
103    }
104
105
106   /** This method adds escape '\' for the Namecomponent if neccessary
107    */
108   private String addEscape( String value )
109   {
110        StringBuffer theNewValue;
111        if( (value != null) && ( (value.indexOf('.') != -1 ) ||
112                                 (value.indexOf('/') != -1)))
113        {
114            char c;
115            theNewValue = new StringBuffer( );
116            for( int i = 0; i < value.length( ); i++ ) {
117                c = value.charAt( i );
118                if( ( c != '.' ) && (c != '/' ) )
119                {
120                    theNewValue.append( c );
121                }
122                else {
123                    // Adding escape for the "."
124                    theNewValue.append( '\\' );
125                    theNewValue.append( c );
126                }
127            }
128        }
129        else {
130            return value;
131        }
132        return new String( theNewValue );
133   }
134
135   /**
136     * Method which converts the Stringified name into Array of Name Components.
137     *
138     * @param string which is the stringified name.
139     * @return  Array of Name Components (Simple or Compound Names)
140     */
141   public org.omg.CosNaming.NameComponent[] convertToNameComponent(
142       String theStringifiedName )
143       throws org.omg.CosNaming.NamingContextPackage.InvalidName
144   {
145        String[] theStringifiedNameComponents =
146                 breakStringToNameComponents( theStringifiedName );
147        if( ( theStringifiedNameComponents == null )
148         || (theStringifiedNameComponents.length == 0 ) )
149        {
150            return null;
151        }
152        NameComponent[] theNameComponents =
153            new NameComponent[theStringifiedNameComponents.length];
154        for( int i = 0; i < theStringifiedNameComponents.length; i++ ) {
155            theNameComponents[i] = createNameComponentFromString(
156                theStringifiedNameComponents[i] );
157        }
158        return theNameComponents;
159   }
160
161   /** Step1 in converting Stringified name into  array of Name Component
162     * is breaking the String into multiple name components
163     */
164   private String[] breakStringToNameComponents( String theStringifiedName ) {
165       int[] theIndices = new int[100];
166       int theIndicesIndex = 0;
167
168       for(int index = 0; index <= theStringifiedName.length(); ) {
169           theIndices[theIndicesIndex] = theStringifiedName.indexOf( '/',
170                index );
171           if( theIndices[theIndicesIndex] == -1 ) {
172               // This is the end of all the occurence of '/' and hence come
173               // out of the loop
174               index = theStringifiedName.length()+1;
175           }
176           else {
177               // If the '/' is found, first check whether it is
178               // preceded by escape '\'
179               // If not then set theIndices and increment theIndicesIndex
180               // and also set the index else just ignore the '/'
181               if( (theIndices[theIndicesIndex] > 0 )
182               && (theStringifiedName.charAt(
183                   theIndices[theIndicesIndex]-1) == '\\') )
184               {
185                  index = theIndices[theIndicesIndex] + 1;
186                  theIndices[theIndicesIndex] = -1;
187               }
188               else {
189                  index = theIndices[theIndicesIndex] + 1;
190                  theIndicesIndex++;
191               }
192           }
193        }
194        if( theIndicesIndex == 0 ) {
195            String[] tempString = new String[1];
196            tempString[0] = theStringifiedName;
197            return tempString;
198        }
199        if( theIndicesIndex != 0 ) {
200            theIndicesIndex++;
201        }
202        return StringComponentsFromIndices( theIndices, theIndicesIndex,
203                                            theStringifiedName );
204    }
205
206   /** This method breaks one big String into multiple substrings based
207     * on the array of index passed in.
208     */
209   private String[] StringComponentsFromIndices( int[] theIndices,
210          int indicesCount, String theStringifiedName )
211   {
212       String[] theStringComponents = new String[indicesCount];
213       int firstIndex = 0;
214       int lastIndex = theIndices[0];
215       for( int i = 0; i < indicesCount; i++ ) {
216           theStringComponents[i] = theStringifiedName.substring( firstIndex,
217             lastIndex );
218           if( ( theIndices[i] < theStringifiedName.length() - 1 )
219             &&( theIndices[i] != -1 ) )
220           {
221               firstIndex = theIndices[i]+1;
222           }
223           else {
224               firstIndex = 0;
225               i = indicesCount;
226           }
227           if( (i+1 < theIndices.length)
228            && (theIndices[i+1] < (theStringifiedName.length() - 1))
229            && (theIndices[i+1] != -1) )
230           {
231               lastIndex = theIndices[i+1];
232           }
233           else {
234               i = indicesCount;
235           }
236           // This is done for the last component
237           if( firstIndex != 0 && i == indicesCount ) {
238               theStringComponents[indicesCount-1] =
239               theStringifiedName.substring( firstIndex );
240           }
241       }
242       return theStringComponents;
243   }
244
245   /** Step 2: After Breaking the Stringified name into set of NameComponent
246     * Strings, The next step is to create Namecomponents from the substring
247     * by removing the escapes if there are any.
248     */
249   private NameComponent createNameComponentFromString(
250        String theStringifiedNameComponent )
251        throws org.omg.CosNaming.NamingContextPackage.InvalidName
252
253   {
254        String id = null;
255        String kind = null;
256        if( ( theStringifiedNameComponent == null )
257         || ( theStringifiedNameComponent.length( ) == 0)
258         || ( theStringifiedNameComponent.endsWith(".") ) )
259        {
260            // If any of the above is true, then we create an invalid Name
261            // Component to indicate that it is an invalid name.
262            throw new org.omg.CosNaming.NamingContextPackage.InvalidName( );
263        }
264
265        int index = theStringifiedNameComponent.indexOf( '.', 0 );
266        // The format could be XYZ (Without kind)
267        if( index == -1 ) {
268            id = theStringifiedNameComponent;
269        }
270        // The format is .XYZ (Without ID)
271        else if( index == 0 ) {
272            // This check is for the Namecomponent which is just "." meaning Id
273            // and Kinds are null
274            if( theStringifiedNameComponent.length( ) != 1 ) {
275                kind = theStringifiedNameComponent.substring(1);
276            }
277        }
278        else
279        {
280            if( theStringifiedNameComponent.charAt(index-1) != '\\' ) {
281                id = theStringifiedNameComponent.substring( 0, index);
282                kind = theStringifiedNameComponent.substring( index + 1 );
283            }
284            else {
285                boolean kindfound = false;
286                while( (index < theStringifiedNameComponent.length() )
287                     &&( kindfound != true ) )
288                {
289                    index = theStringifiedNameComponent.indexOf( '.',index + 1);
290                    if( index > 0 ) {
291                        if( theStringifiedNameComponent.charAt(
292                                index - 1 ) != '\\' )
293                        {
294                            kindfound = true;
295                        }
296                    }
297                    else
298                    {
299                        // No more '.', which means there is no Kind
300                        index = theStringifiedNameComponent.length();
301                    }
302                }
303                if( kindfound == true ) {
304                    id = theStringifiedNameComponent.substring( 0, index);
305                    kind = theStringifiedNameComponent.substring(index + 1 );
306                }
307                else {
308                    id = theStringifiedNameComponent;
309                }
310            }
311        }
312        id = cleanEscapeCharacter( id );
313        kind = cleanEscapeCharacter( kind );
314        if( id == null ) {
315                id = "";
316        }
317        if( kind == null ) {
318                kind = "";
319        }
320        return new NameComponent( id, kind );
321   }
322
323
324   /** This method cleans the escapes in the Stringified name and returns the
325     * correct String
326     */
327   private String cleanEscapeCharacter( String theString )
328   {
329        if( ( theString == null ) || (theString.length() == 0 ) ) {
330                return theString;
331        }
332        int index = theString.indexOf( '\\' );
333        if( index == 0 ) {
334            return theString;
335        }
336        else {
337            StringBuffer src = new StringBuffer( theString );
338            StringBuffer dest = new StringBuffer( );
339            char c;
340            for( int i = 0; i < theString.length( ); i++ ) {
341                c = src.charAt( i );
342                if( c != '\\' ) {
343                    dest.append( c );
344                } else {
345                    if( i+1 < theString.length() ) {
346                        char d = src.charAt( i + 1 );
347                        // If there is a AlphaNumeric character after a \
348                        // then include slash, as it is not intended as an
349                        // escape character.
350                        if( Character.isLetterOrDigit(d) ) {
351                            dest.append( c );
352                        }
353                    }
354                }
355            }
356            return new String(dest);
357        }
358   }
359
360   /**
361     * Method which converts the Stringified name  and Host Name Address into
362     * a URL based Name
363     *
364     * @param address which is ip based host name
365     * @param name which is the stringified name.
366     * @return  url based Name.
367     */
368    public String createURLBasedAddress( String address, String name )
369        throws InvalidAddress
370    {
371        String theurl = null;
372        if( ( address == null )
373          ||( address.length() == 0 ) ) {
374            throw new InvalidAddress();
375        }
376        else {
377            theurl = "corbaname:" + address + "#" + encode( name );
378        }
379        return theurl;
380    }
381
382    /** Encodes the string according to RFC 2396 IETF spec required by INS.
383     */
384    private String encode( String stringToEncode ) {
385        StringWriter theStringAfterEscape = new StringWriter();
386        int byteCount = 0;
387        for( int i = 0; i < stringToEncode.length(); i++ )
388        {
389            char c = stringToEncode.charAt( i ) ;
390            if( Character.isLetterOrDigit( c ) ) {
391                theStringAfterEscape.write( c );
392            }
393            // Do no Escape for characters in this list
394            // RFC 2396
395            else if((c == ';') || (c == '/') || (c == '?')
396            || (c == ':') || (c == '@') || (c == '&') || (c == '=')
397            || (c == '+') || (c == '$') || (c == ';') || (c == '-')
398            || (c == '_') || (c == '.') || (c == '!') || (c == '~')
399            || (c == '*') || (c == ' ') || (c == '(') || (c == ')') )
400            {
401                theStringAfterEscape.write( c );
402            }
403            else {
404                // Add escape
405                theStringAfterEscape.write( '%' );
406                String hexString = Integer.toHexString( (int) c );
407                theStringAfterEscape.write( hexString );
408            }
409        }
410        return theStringAfterEscape.toString();
411    }
412
413}
414