001    /* ====================================================================
002     * The Apache Software License, Version 1.1
003     *
004     * Copyright (c) 2003 The Apache Software Foundation.  All rights
005     * reserved.
006     *
007     * Redistribution and use in source and binary forms, with or without
008     * modification, are permitted provided that the following conditions
009     * are met:
010     *
011     * 1. Redistributions of source code must retain the above copyright
012     *    notice, this list of conditions and the following disclaimer.
013     *
014     * 2. Redistributions in binary form must reproduce the above copyright
015     *    notice, this list of conditions and the following disclaimer in
016     *    the documentation and/or other materials provided with the
017     *    distribution.
018     *
019     * 3. The end-user documentation included with the redistribution,
020     *    if any, must include the following acknowledgment:
021     *       "This product includes software developed by the
022     *        Apache Software Foundation (http://www.apache.org/)."
023     *    Alternately, this acknowledgment may appear in the software itself,
024     *    if and wherever such third-party acknowledgments normally appear.
025     *
026     * 4. The names "The Jakarta Project", "Commons", and "Apache Software
027     *    Foundation" must not be used to endorse or promote products derived
028     *    from this software without prior written permission. For written
029     *    permission, please contact apache@apache.org.
030     *
031     * 5. Products derived from this software may not be called "Apache",
032     *    nor may "Apache" appear in their name, without prior written
033     *    permission of the Apache Software Foundation.
034     *
035     * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036     * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037     * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038     * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039     * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040     * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041     * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042     * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043     * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044     * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046     * SUCH DAMAGE.
047     * ====================================================================
048     *
049     * This software consists of voluntary contributions made by many
050     * individuals on behalf of the Apache Software Foundation.  For more
051     * information on the Apache Software Foundation, please see
052     * <http://www.apache.org/>.
053     *
054     */
055    package org.jpu.patterns.serviceLocator;
056    
057    import java.util.Properties;
058    
059    /**
060     * Base class for all the locators in this package.  These classes are
061     * extensible service locators that obtain--and optionally cache--references to 
062     * various J2EE objects such as session beans, home objects, and data sources.  
063     * They can also handle narrowing as appropriate 
064     * and repackage the J2EE exceptions into a 
065     * {@link ServiceLocatorException}.
066     * <p>
067     * In general these locators will just hand you the object you want
068     * and from there it's up to you; however, {@link SLSBLocator} will
069     * also use reflection to call the <code>create()</code> method, which
070     * (because the EJB is stateless) takes no arguments, and give you a
071     * reference to the SLSB itself, rather than its home.  The EJB's
072     * remote reference, rather than its home, will then be returned (and optionally cached
073     * for subsequent requests).
074     * <p>
075     * The locators in this package <i>are not</i> implemented as singletons, in order
076     * to minimize assumptions about the application in which they are
077     * used and allow the developer to maintain locator instances any way he
078     * chooses.  However, in the subpackage {@link org.jpu.patterns.serviceLocator.onePerContext}
079     * are versions that use the {@link org.jpu.patterns.singleton.onePerContext.OnePerContextManager}
080     * facility and define appropriate public <code>getInstance()</code> methods as
081     * described in {@link org.jpu.patterns.singleton.onePerContext.OnePerContextManager}.  You can
082     * use these just like you would a traditional singleton, or you can supply an optional
083     * "context" parameter to the <code>getInstance()</code> calls.
084     * <p>
085     * The {@link ServiceLocatorOptions} class can be used by the client to
086     * govern the behavior of the public methods with respect to a single
087     * lookup.  Among other options, the client can indicate that the
088     * lookup should bypass the cache.
089     * <p>
090     * <b>Strategies</b><br>
091     * By default the actual JNDI lookup is based on 
092     * "<code>InitialContext.lookup()</code>", but you can change this by supplying your own {@link ILookupStrategy}
093     * via {@link #setLookupStrategy}.
094     * <p>
095     * The default caching implementation is a "null" cache, which does no caching, but
096     * you can change this by supplying your own {@link Cache} via {@link #setCache}.
097     * <p>
098     * The default approach to narrowing is based on <code>PortableRemoteObject.narrow()</code>, but
099     * you can change this by supplying your own {@link ILocator.INarrowStrategy} via 
100     * {@link #setNarrowStrategy}.
101     * <p>
102     * <b>InitialContext Properties</b><br>
103     * For JNDI-based lookups, the caller must always specify the JNDI name to
104     * be passed to <code>InitialContext.lookup()</code>.  In addition, these service locators give 
105     * you the option of explicitly specifying a naming provider URL, initial
106     * context factory, or any other properies interpreted by <code>InitialContext</code>.  You can do this 
107     * either by explicitly adjusting the <code>Properties</code>
108     * instance associated with the {@link ILookupStrategy} (which would affect all lookups performed by
109     * that strategy),  or by using the following special syntax for the naming identifiers (which only affects a single lookup operation):
110     * <pre>
111     * <i>jndiName</i>{;<i>name</i>=<i>value</i>}*
112     * </pre>
113     * where <i>name</i> is a property name and <i>value</i> is its value.  Here is an example illustrating
114     * an LDAP lookup:
115     * <pre>
116     * <code>
117     * MyQueue;java.naming.factory.initial=com.sun.jndi.ldap.LdapCtxFactory;java.naming.provider.url=ldap://ldap.foo.com:389/ou=myqueues,o=foo.com,c=us
118     * </code>
119     * </pre>
120     * <p>
121     * Thus these service locators allow your application to reference objects defined in any
122     * number of different naming directories and refer to all these objects via simple strings.
123     * Of course these strings would normally reside in an external configuration source.
124     * <p>
125     * Properties passed using the above syntax override any settings in the {@link ILookupStrategy}'s
126     * <code>Properties</code> instance, which in turn override any "java.naming" system properties.
127     */
128    public interface ILocator {
129            public interface IIdentifierParser {
130                    public String getName();
131                    public Properties getProperties();
132                    public String getIdentifier();
133            }
134    
135        /**
136         * Defines the interface that the cache must fulfill.  
137         */
138        public static interface ICache {
139            public Object get(String namingIdentifier);
140            public void clear();
141            public void remove(String namingIdentifier);
142            public void put(String namingIdentifier, Object obj);
143        }
144    
145            /**
146             * Defines the interface for strategies that perform the actual lookup of objects (usually but not
147             * necessarily using JNDI).  The default implementation {@link Locator.DefaultLookupStrategy} uses
148             * JNDI.  
149             */
150        public static interface ILookupStrategy {
151    
152                    public Properties getProperties();
153    
154                    /**
155                     * Looks up the object with the given name and returns it, or throws an exception if it can't   
156                     * be found.  The {@link ServiceLocatorOptions} object passed to {@link #getObject(String)}
157                     * is passed to this method.
158                     * <p>
159                     * This method <i>should not</i> narrow the object as that will be done by the caller.
160                     */
161            public Object lookup(String namingIdentifier, ServiceLocatorOptions options) throws ServiceLocatorException;
162        }
163    
164            /**
165             * Defines the interface for strategies that narrow objects.  Narrowing is necessary for
166             * remote objects and is usually done through "<code>PortableRemoteObject.narrow()</code>".
167             * The default implementation {@link Locator.DefaultNarrowStrategy} uses this form of narrowing.
168             * To set your own narrow strategy, either override {@link #newNarrowStrategy()} or call
169             * {@link #setNarrowStrategy}.
170             */
171        public static interface INarrowStrategy {
172            /**
173             * Narrows the given object to the given type.  If either <code>o</code> or
174             * <code>c</code> are <code>null</code>, this method returns <code>o</code>.
175             * Otherwise it attempts to narrow using <code>PortableRemoteObject.narrow()</code>
176             * and rethrows any exceptions as <code>ServiceLocatorException</code>, wrapping
177             * the original exception.
178             * <p>
179             * Subclasses are free to override this method; in particular, local homes 
180             * should not be narrowed using <code>PortableRemoteObject.narrow()</code>.
181             */
182            public Object narrow(Object o, Class c) throws ServiceLocatorException;
183        }
184    
185        /**
186         * Removes the object with the specified JNDI name from the cache.
187         */
188        public void removeFromCache(String namingIdentifier);
189    
190        /**
191         * Removes all items from the cache.
192         */
193        public void clearCache();
194    
195        /**
196         * Convenience alias for "<code>getObject( namingIdentifier, new ServiceLocatorOptions().setCastTo(c) )</code>".
197         * See {@link #getObject(String, ServiceLocatorOptions)}.
198         */
199        public Object getObject(String namingIdentifier, Class c) throws ServiceLocatorException;
200    
201        /**
202         * Convenience alias for "<code>getObject(namingIdentifier, (ServiceLocatorOptions)null)</code>".
203         * See {@link #getObject(String, ServiceLocatorOptions)}.
204         */
205        public Object getObject(String namingIdentifier) throws ServiceLocatorException;
206    
207        /**
208         * Attempts to find the object with the given JNDI name using the given options.
209         * <p>
210         * The method first checks the cache for an object with the given JNDI name, unless
211         * <code>options.noCache</code> is <code>true</code> in which case the cache is
212         * bypassed.  If the object is not in the cache or the cache is being bypassed,
213         * the method will attempt to find the object using the protected <code>lookup()</code>
214         * method (which subclasses can override).  Any exception thrown from that method
215         * will be allowed to propagate from this method.  Any object found through 
216         * JNDI is automatically entered into the cache via its public <code>put()</code>
217         * method.
218         * <p>
219         * If the object is found, either in the cache or via JNDI lookup, then if a narrow 
220         * type is defined, either via <code>options.castTo</code> or 
221         * {@link #getDefaultCast()}, the method will
222         * attempt to narrow the object to that type using the protected <code>narrow()</code>
223         * method (which subclasses are free to override).  Narrow's default 
224         * implementation uses <code>PortableRemoteObject.narrow()</code>.
225         * <p>
226         * If the named object cannot be found, or if the narrow fails, 
227         * {@link ServiceLocatorException} is
228         * thrown wrapping the underlying JNDI exception.  
229         * <p>
230         */
231        public Object getObject(String namingIdentifier, ServiceLocatorOptions options) throws ServiceLocatorException;
232    
233        /**
234         * Sets the cache, replacing the previous cache (and hence causing loss of previously
235         * cached objects).
236         */
237        public void setCache(ICache cache);
238    
239        /**
240         * Returns the cache.  The returned object is unsynchronized, so the caller should synchronize on
241             * "<code>this</code>" while querying or modifying it.
242             */
243        public ICache getCache();
244    
245        /**
246         * Sets the {@link ILocator.INarrowStrategy}, replacing the previous one.
247         */
248        public void setNarrowStrategy(INarrowStrategy ls);
249    
250        /**
251         * Returns the current {@link ILocator.INarrowStrategy}.  
252         */
253        public INarrowStrategy getNarrowStrategy();
254    
255        /**
256         * Sets the {@link ILocator.ILookupStrategy}, replacing the previous one.
257         */
258        public void setLookupStrategy(ILookupStrategy ls);
259    
260        /**
261         * Returns the current {@link ILocator.ILookupStrategy}.  
262         */
263        public ILookupStrategy getLookupStrategy();
264    
265        /**
266         * By default instantiates a {@link Locator.NullCache}, but subclasses can 
267         * override to supply their own cache implementation.
268         */
269        public ICache newCache();
270    
271        /**
272         * By default instantiates a {@link Locator.DefaultLookupStrategy}, but subclasses can 
273         * override to supply their own {@link ILocator.ILookupStrategy} implementation.
274         */
275        public ILookupStrategy newLookupStrategy();
276    
277        /**
278         * By default instantiates a {@link Locator.DefaultNarrowStrategy}, but subclasses can 
279         * override to supply their own {@link ILocator.INarrowStrategy} implementation.
280         */
281        public INarrowStrategy newNarrowStrategy();
282    
283        /**
284         * If <code>options.castTo</code> is not <code>null</code>, call {@link org.jpu.patterns.serviceLocator.Locator#narrow(Object,Class)}
285         * variant to narrow the given object to this type and return the result; else if 
286         * {@link #getDefaultCast()} is not <code>null</code>, call {@link org.jpu.patterns.serviceLocator.Locator#narrow(Object,Class)}
287         * variant to narrow to this type and return the result;
288         * else return the original object passed via "<code>o</code>".
289         */
290        public Object narrow(Object o, ServiceLocatorOptions options) throws ServiceLocatorException;
291    
292        /**
293         * Simply calls "<code>getNarrowStrategy().narrow(o, c)</code>".  If you wish to   
294         * change the way narrowing is performed, write your own {@link ILocator.INarrowStrategy} and either override
295         * {@link #newNarrowStrategy()} to instantiate it, or call the public {@link #setNarrowStrategy(ILocator.INarrowStrategy)}
296         * method to replace the existing strategy.
297         */
298        public Object narrow(Object o, Class c) throws ServiceLocatorException;
299    
300        /**
301         * By default returns <code>null</code>, but subclasses can override to 
302         * return the <code>Class</code> that should be passed as the second parameter
303         * to {@link #narrow(Object,Class)} if no class is passed via
304         * the <code>castTo</code> attribute of the {@link ServiceLocatorOptions} 
305         * instance.  If both <code>castTo</code> and the return value of this method
306         * are <code>null</code>, no cast is performed.
307         */
308        public Class getDefaultCast();
309    }
310    
311