001// Copyright 2004, 2005 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.hivemind.lib.impl;
016
017import java.util.Hashtable;
018
019import javax.naming.Context;
020import javax.naming.InitialContext;
021import javax.naming.NamingException;
022
023import org.apache.hivemind.ApplicationRuntimeException;
024import org.apache.hivemind.HiveMind;
025import org.apache.hivemind.lib.NameLookup;
026import org.apache.hivemind.lib.RemoteExceptionCoordinator;
027import org.apache.hivemind.lib.RemoteExceptionEvent;
028import org.apache.hivemind.lib.RemoteExceptionListener;
029
030/**
031 * Standard implementation of the {@link org.apache.hivemind.lib.NameLookup}
032 * service interface.
033 *
034 * @author Howard Lewis Ship
035 */
036public class NameLookupImpl implements NameLookup, RemoteExceptionListener
037{
038    private RemoteExceptionCoordinator _coordinator;
039    private Context _initialContext;
040    private String _initialFactory;
041    private String _URLPackages;
042    private String _providerURL;
043
044    public Object lookup(String name, Class expected)
045    {
046        int i = 0;
047
048        while (true)
049        {
050            Context context = null;
051            Object raw = null;
052
053            try
054            {
055                context = getInitialContext();
056
057                raw = context.lookup(name);
058            }
059            catch (NamingException ex)
060            {
061                if (i++ == 0)
062                    _coordinator.fireRemoteExceptionDidOccur(this, ex);
063                else
064                    throw new ApplicationRuntimeException(
065                        ImplMessages.unableToLookup(name, context),
066                        ex);
067                continue;
068            }
069
070            if (raw == null)
071                throw new ApplicationRuntimeException(ImplMessages.noObject(name, expected));
072
073            if (!expected.isAssignableFrom(raw.getClass()))
074                throw new ApplicationRuntimeException(ImplMessages.wrongType(name, raw, expected));
075
076            return raw;
077        }
078    }
079
080    private Context getInitialContext() throws NamingException
081    {
082        if (_initialContext == null)
083        {
084
085            Hashtable properties = new Hashtable();
086
087            if (!HiveMind.isBlank(_initialFactory))
088                properties.put(Context.INITIAL_CONTEXT_FACTORY, _initialFactory);
089
090            if (!HiveMind.isBlank(_providerURL))
091                properties.put(Context.PROVIDER_URL, _providerURL);
092
093            if (!HiveMind.isBlank(_URLPackages))
094                properties.put(Context.URL_PKG_PREFIXES, _URLPackages);
095
096            _initialContext = constructContext(properties);
097        }
098
099        return _initialContext;
100    }
101
102    /**
103     * Constructs the InitialContext (this is separated out in a standalone
104     * method so that it may be overridden in a testing subclass).
105     */
106    protected Context constructContext(Hashtable properties) throws NamingException
107    {
108        return new InitialContext(properties);
109    }
110
111    /**
112     * Sets the InitialContext to null.
113     */
114    public void remoteExceptionDidOccur(RemoteExceptionEvent event)
115    {
116        _initialContext = null;
117    }
118
119    /**
120     * Sets the initial factory used to create the initial JNDI context.
121     * Equivalent to the system property <code>java.naming.factory.initial</code>.
122     */
123    public void setInitialFactory(String string)
124    {
125        _initialFactory = string;
126    }
127
128    /**
129     * Sets the JNDI provider URL, used to create the initial JNDI context.
130     * Equivalent to the system property <code>java.naming.provider.url</code>.
131     */
132    public void setProviderURL(String string)
133    {
134        _providerURL = string;
135    }
136
137    /**
138     * Sets the URL packages, used to create the initial JNDI context.
139     * Equivalent to the system property
140     * <code>java.naming.factory.url.pkgs</code>
141     */
142
143    public void setURLPackages(String string)
144    {
145        _URLPackages = string;
146    }
147
148    public void setCoordinator(RemoteExceptionCoordinator coordinator)
149    {
150        _coordinator = coordinator;
151    }
152
153}