INSURLOperationImpl.java revision 608:7e06bf1dcb09
1/*
2 * Copyright (c) 1998, 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.impl.resolver;
27
28import java.util.List ;
29import java.util.Map ;
30import java.util.Comparator ;
31import java.util.Iterator ;
32import java.util.HashMap ;
33import java.util.ArrayList ;
34import java.util.Collections ;
35
36import org.omg.CosNaming.NamingContextExt ;
37import org.omg.CosNaming.NamingContextExtHelper ;
38
39import sun.corba.EncapsInputStreamFactory;
40
41import com.sun.corba.se.spi.ior.IOR;
42import com.sun.corba.se.spi.ior.IORTemplate;
43import com.sun.corba.se.spi.ior.ObjectKey;
44import com.sun.corba.se.spi.ior.IORFactories;
45import com.sun.corba.se.spi.ior.ObjectKeyFactory ;
46import com.sun.corba.se.spi.ior.iiop.IIOPAddress;
47import com.sun.corba.se.spi.ior.iiop.IIOPProfile ;
48import com.sun.corba.se.spi.ior.iiop.IIOPProfileTemplate ;
49import com.sun.corba.se.spi.ior.iiop.IIOPFactories ;
50import com.sun.corba.se.spi.ior.iiop.GIOPVersion;
51import com.sun.corba.se.spi.ior.iiop.AlternateIIOPAddressComponent;
52import com.sun.corba.se.spi.logging.CORBALogDomains ;
53import com.sun.corba.se.spi.orb.Operation;
54import com.sun.corba.se.spi.orb.ORB;
55import com.sun.corba.se.spi.resolver.Resolver;
56
57import com.sun.corba.se.impl.encoding.EncapsInputStream;
58import com.sun.corba.se.impl.logging.ORBUtilSystemException;
59import com.sun.corba.se.impl.logging.OMGSystemException;
60import com.sun.corba.se.impl.naming.namingutil.INSURLHandler;
61import com.sun.corba.se.impl.naming.namingutil.IIOPEndpointInfo;
62import com.sun.corba.se.impl.naming.namingutil.INSURL;
63import com.sun.corba.se.impl.naming.namingutil.CorbalocURL;
64import com.sun.corba.se.impl.naming.namingutil.CorbanameURL;
65import com.sun.corba.se.impl.orbutil.ORBConstants;
66import com.sun.corba.se.impl.orbutil.ORBUtility;
67
68/**
69 * This class provides an Operation that converts from CORBA INS URL strings into
70 * CORBA object references.  It will eventually become extensible, but for now it
71 * simply encapsulates the existing implementation.  Once the full extensibility
72 * is in place, we want this operation to convert string to INSURL, which has mainly
73 * a public resolver method that returns an object reference.
74 *
75 * @author  Hemanth
76 * @author  Ken
77 */
78public class INSURLOperationImpl implements Operation
79{
80    ORB orb;
81    ORBUtilSystemException wrapper ;
82    OMGSystemException omgWrapper ;
83    Resolver bootstrapResolver ;
84
85    // Root Naming Context for default resolution of names.
86    private NamingContextExt rootNamingContextExt;
87    private Object rootContextCacheLock = new Object() ;
88
89    // The URLHandler to parse INS URL's
90    private INSURLHandler insURLHandler = INSURLHandler.getINSURLHandler() ;
91
92    public INSURLOperationImpl( ORB orb, Resolver bootstrapResolver )
93    {
94        this.orb = orb ;
95        wrapper = ORBUtilSystemException.get( orb,
96            CORBALogDomains.ORB_RESOLVER ) ;
97        omgWrapper = OMGSystemException.get( orb,
98            CORBALogDomains.ORB_RESOLVER ) ;
99        this.bootstrapResolver = bootstrapResolver ;
100    }
101
102    private static final int NIBBLES_PER_BYTE = 2 ;
103    private static final int UN_SHIFT = 4 ; // "UPPER NIBBLE" shift factor for <<
104
105    /** This static method takes a Stringified IOR and converts it into IOR object.
106      * It is the caller's responsibility to only pass strings that start with "IOR:".
107      */
108    private org.omg.CORBA.Object getIORFromString( String str )
109    {
110        // Length must be even for str to be valid
111        if ( (str.length() & 1) == 1 )
112            throw wrapper.badStringifiedIorLen() ;
113
114        byte[] buf = new byte[(str.length() - ORBConstants.STRINGIFY_PREFIX.length()) / NIBBLES_PER_BYTE];
115        for (int i=ORBConstants.STRINGIFY_PREFIX.length(), j=0; i < str.length(); i +=NIBBLES_PER_BYTE, j++) {
116             buf[j] = (byte)((ORBUtility.hexOf(str.charAt(i)) << UN_SHIFT) & 0xF0);
117             buf[j] |= (byte)(ORBUtility.hexOf(str.charAt(i+1)) & 0x0F);
118        }
119        EncapsInputStream s = EncapsInputStreamFactory.newEncapsInputStream(orb, buf, buf.length,
120                orb.getORBData().getGIOPVersion());
121        s.consumeEndian();
122        return s.read_Object() ;
123    }
124
125    public Object operate( Object arg )
126    {
127        if (arg instanceof String) {
128            String str = (String)arg ;
129
130            if (str.startsWith( ORBConstants.STRINGIFY_PREFIX ))
131                // XXX handle this as just another URL scheme
132                return getIORFromString( str ) ;
133            else {
134                INSURL insURL = insURLHandler.parseURL( str ) ;
135                if (insURL == null)
136                    throw omgWrapper.soBadSchemeName() ;
137                return resolveINSURL( insURL ) ;
138            }
139        }
140
141        throw wrapper.stringExpected() ;
142    }
143
144    private org.omg.CORBA.Object resolveINSURL( INSURL theURLObject ) {
145        // XXX resolve should be a method on INSURL
146        if( theURLObject.isCorbanameURL() ) {
147            return resolveCorbaname( (CorbanameURL)theURLObject );
148        } else {
149            return resolveCorbaloc( (CorbalocURL)theURLObject );
150        }
151    }
152
153    /**
154     *  resolves a corbaloc: url that is encapsulated in a CorbalocURL object.
155     *
156     *  @return the CORBA.Object if resolution is successful
157     */
158    private org.omg.CORBA.Object resolveCorbaloc(
159        CorbalocURL theCorbaLocObject )
160    {
161        org.omg.CORBA.Object result = null;
162        // If RIR flag is true use the Bootstrap protocol
163        if( theCorbaLocObject.getRIRFlag( ) )  {
164            result = bootstrapResolver.resolve(theCorbaLocObject.getKeyString());
165        } else {
166            result = getIORUsingCorbaloc( theCorbaLocObject );
167        }
168
169        return result;
170    }
171
172    /**
173     *  resolves a corbaname: url that is encapsulated in a CorbanameURL object.
174     *
175     *  @return the CORBA.Object if resolution is successful
176     */
177    private org.omg.CORBA.Object resolveCorbaname( CorbanameURL theCorbaName ) {
178        org.omg.CORBA.Object result = null;
179
180        try {
181            NamingContextExt theNamingContext = null;
182
183            if( theCorbaName.getRIRFlag( ) ) {
184                // Case 1 of corbaname: rir#
185                theNamingContext = getDefaultRootNamingContext( );
186            } else {
187                // Case 2 of corbaname: ::hostname#
188                org.omg.CORBA.Object corbalocResult =
189                    getIORUsingCorbaloc( theCorbaName );
190                if( corbalocResult == null ) {
191                    return null;
192                }
193
194                theNamingContext =
195                    NamingContextExtHelper.narrow( corbalocResult );
196            }
197
198            String StringifiedName = theCorbaName.getStringifiedName( );
199
200            if( StringifiedName == null ) {
201                // This means return the Root Naming context
202                return theNamingContext;
203            } else {
204                return theNamingContext.resolve_str( StringifiedName );
205            }
206        } catch( Exception e ) {
207            clearRootNamingContextCache( );
208            return null;
209        }
210     }
211
212    /**
213     *  This is an internal method to get the IOR from the CorbalocURL object.
214     *
215     *  @return the CORBA.Object if resolution is successful
216     */
217     private org.omg.CORBA.Object getIORUsingCorbaloc( INSURL corbalocObject )
218     {
219        Map     profileMap = new HashMap();
220        List    profileList1_0 = new ArrayList();
221
222        // corbalocObject cannot be null, because it's validated during
223        // parsing. So no null check is required.
224        java.util.List theEndpointInfo = corbalocObject.getEndpointInfo();
225        String theKeyString = corbalocObject.getKeyString();
226        // If there is no KeyString then it's invalid
227        if( theKeyString == null ) {
228            return null;
229        }
230
231        ObjectKey key = orb.getObjectKeyFactory().create(
232            theKeyString.getBytes() );
233        IORTemplate iortemp = IORFactories.makeIORTemplate( key.getTemplate() );
234        java.util.Iterator iterator = theEndpointInfo.iterator( );
235        while( iterator.hasNext( ) ) {
236            IIOPEndpointInfo element =
237                (IIOPEndpointInfo) iterator.next( );
238            IIOPAddress addr = IIOPFactories.makeIIOPAddress( orb, element.getHost(),
239                element.getPort() );
240            GIOPVersion giopVersion = GIOPVersion.getInstance( (byte)element.getMajor(),
241                                             (byte)element.getMinor());
242            IIOPProfileTemplate profileTemplate = null;
243            if (giopVersion.equals(GIOPVersion.V1_0)) {
244                profileTemplate = IIOPFactories.makeIIOPProfileTemplate(
245                    orb, giopVersion, addr);
246                profileList1_0.add(profileTemplate);
247            } else {
248                if (profileMap.get(giopVersion) == null) {
249                    profileTemplate = IIOPFactories.makeIIOPProfileTemplate(
250                        orb, giopVersion, addr);
251                    profileMap.put(giopVersion, profileTemplate);
252                } else {
253                    profileTemplate = (IIOPProfileTemplate)profileMap.get(giopVersion);
254                    AlternateIIOPAddressComponent iiopAddressComponent =
255                                IIOPFactories.makeAlternateIIOPAddressComponent(addr);
256                    profileTemplate.add(iiopAddressComponent);
257                }
258            }
259        }
260
261        GIOPVersion giopVersion = orb.getORBData().getGIOPVersion();
262        IIOPProfileTemplate pTemplate = (IIOPProfileTemplate)profileMap.get(giopVersion);
263        if (pTemplate != null) {
264            iortemp.add(pTemplate); // Add profile for GIOP version used by this ORB
265            profileMap.remove(giopVersion); // Now remove this value from the map
266        }
267
268        // Create a comparator that can sort in decending order (1.2, 1.1, ...)
269        Comparator comp = new Comparator() {
270            public int compare(Object o1, Object o2) {
271                GIOPVersion gv1 = (GIOPVersion)o1;
272                GIOPVersion gv2 = (GIOPVersion)o2;
273                return (gv1.lessThan(gv2) ? 1 : (gv1.equals(gv2) ? 0 : -1));
274            };
275        };
276
277        // Now sort using the above comparator
278        List list = new ArrayList(profileMap.keySet());
279        Collections.sort(list, comp);
280
281        // Add the profiles in the sorted order
282        Iterator iter = list.iterator();
283        while (iter.hasNext()) {
284            IIOPProfileTemplate pt = (IIOPProfileTemplate)profileMap.get(iter.next());
285            iortemp.add(pt);
286        }
287
288        // Finally add the 1.0 profiles
289        iortemp.addAll(profileList1_0);
290
291        IOR ior = iortemp.makeIOR( orb, "", key.getId() ) ;
292        return ORBUtility.makeObjectReference( ior ) ;
293    }
294
295    /**
296     *  This is required for corbaname: resolution. Currently we
297     *  are not caching RootNamingContext as the reference to rootNamingContext
298     *  may not be Persistent in all the implementations.
299     *  _REVISIT_ to clear the rootNamingContext in case of COMM_FAILURE.
300     *
301     *  @return the org.omg.COSNaming.NamingContextExt if resolution is
302     *   successful
303     *
304     */
305    private NamingContextExt getDefaultRootNamingContext( ) {
306        synchronized( rootContextCacheLock ) {
307            if( rootNamingContextExt == null ) {
308                try {
309                    rootNamingContextExt =
310                        NamingContextExtHelper.narrow(
311                        orb.getLocalResolver().resolve( "NameService" ) );
312                } catch( Exception e ) {
313                    rootNamingContextExt = null;
314                }
315            }
316        }
317        return rootNamingContextExt;
318    }
319
320    /**
321     *  A utility method to clear the RootNamingContext, if there is an
322     *  exception in resolving CosNaming:Name from the RootNamingContext,
323     */
324    private void clearRootNamingContextCache( ) {
325        synchronized( rootContextCacheLock ) {
326            rootNamingContextExt = null;
327        }
328    }
329}
330