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