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.ArrayList;
058 import java.util.Collections;
059 import java.util.HashMap;
060 import java.util.Iterator;
061 import java.util.List;
062 import java.util.Map;
063 import java.util.Properties;
064
065 import javax.naming.InitialContext;
066 import javax.rmi.PortableRemoteObject;
067
068 import org.apache.commons.lang.StringUtils;
069 import org.apache.commons.logging.Log;
070 import org.apache.commons.logging.LogFactory;
071 import org.jpu.patterns.common.JPUStringUtils;
072
073 /**
074 * Implementation of the {@link ILocator} interface. See its documentation for more info.
075 */
076 public class Locator implements ILocator {
077 public class DefaultIdentifierParser implements IIdentifierParser {
078 public DefaultIdentifierParser(String str, Properties props) throws InvalidIdentifierException {
079 List parts = JPUStringUtils.split( str, getDelimeter(), true );
080 int i = 0;
081 _name = (String)parts.get(i++);
082 _props = new Properties();
083 _props.putAll( props );
084 while ( i < parts.size() ) {
085 String part = (String)parts.get(i++);
086 List halves = JPUStringUtils.splitN( part, "=", 2, true );
087 _props.setProperty( (String)halves.get(0), (String)halves.get(1) );
088 }
089 }
090
091 public String getIdentifier() {
092 return toString();
093 }
094
095 public String getName() {
096 return _name;
097 }
098 public Properties getProperties() {
099 return _props;
100 }
101
102 protected String getDelimeter() {
103 return ";";
104 }
105
106 protected String concatJndiProperties( Properties props ) {
107 List parts = new ArrayList();
108 Iterator it = props.entrySet().iterator();
109 while ( it.hasNext() ) {
110 Map.Entry entry = (Map.Entry)it.next();
111 parts.add( "" + entry.getKey() + "=" + entry.getValue() );
112 }
113 Collections.sort(parts);
114 return StringUtils.join( parts.iterator(), getDelimeter() );
115 }
116
117 public String toString() {
118 String str = getName();
119 if ( ! _props.isEmpty() ) {
120 str += getDelimeter() + concatJndiProperties(_props);
121 }
122 return str;
123 }
124 private String _name = null;
125 private Properties _props = new Properties();
126 }
127
128 /**
129 * Simple lookup strategy implementation based on "<code>new InitialContext(System.getProperties()).lookup()</code>".
130 */
131 public static class DefaultLookupStrategy implements ILookupStrategy {
132 public DefaultLookupStrategy(Locator locator) {
133 _locator = locator;
134 }
135 public Properties getProperties() {
136 return _props;
137 }
138
139 protected Properties getJndiProperties( Properties props ) {
140 Iterator it = props.entrySet().iterator();
141 Properties result = new Properties();
142 while ( it.hasNext() ) {
143 Map.Entry entry = (Map.Entry)it.next();
144 String key = "" + entry.getKey();
145 if ( key.startsWith( "java.naming." ) ) {
146 result.put( key, entry.getValue() );
147 }
148 }
149 return result;
150 }
151
152 public Object lookup(String namingIdentifier, ServiceLocatorOptions options) throws ServiceLocatorException {
153 options = ServiceLocatorOptions.defaultIfNull(options);
154 InitialContext ic = null;
155 try {
156 if ( _log.isDebugEnabled() ) {
157 _log.debug( "lookup(namingIdentifier=[" + namingIdentifier + "], options=[" + options + "])" );
158 }
159
160 Properties props = new Properties();
161 props.putAll( System.getProperties() );
162 props.putAll( getProperties() );
163 Properties jndiProps = getJndiProperties( props );
164 IIdentifierParser identifier = _locator.newIdentifier(namingIdentifier, jndiProps);
165 ic = new InitialContext( identifier.getProperties() );
166 Object obj = ic.lookup( identifier.getName() );
167 if ( _log.isDebugEnabled() ) {
168 _log.debug( "lookup() obtained an object of class '" + obj.getClass().getName() + "'" );
169 }
170 return obj;
171 }
172 catch( ServiceLocatorException e ) {
173 throw e;
174 }
175 catch( Exception e ) {
176 throw new ServiceLocatorException(e);
177 }
178 finally {
179 if ( ic != null ) {
180 try { ic.close(); } catch( Throwable t ) {}
181 }
182 }
183 }
184 private Properties _props = new Properties();
185 private Locator _locator = null;
186 private static Log _log = LogFactory.getLog(DefaultLookupStrategy.class);
187 }
188
189 /**
190 * Simple narrow strategy implementation based on "<code>PortableRemoteObject.narrow()</code>".
191 */
192 public static class DefaultNarrowStrategy implements INarrowStrategy {
193 public Object narrow(Object o, Class c) throws ServiceLocatorException {
194 if ( c != null && o != null ) {
195 try {
196 if ( _log.isDebugEnabled() ) {
197 _log.debug( "narrow() is narrowing a '" + o.getClass().getName() + "' to a '" + c.getName() + "'" );
198 }
199 o = PortableRemoteObject.narrow(o, c);
200 }
201 catch( Exception t ) {
202 throw new ServiceLocatorException(t);
203 }
204 }
205 return o;
206 }
207 }
208
209 /**
210 * Simple cache implementation based on <code>HashMap</code>.
211 */
212 public static class NullCache implements ICache {
213 public Object get(String namingIdentifier) {
214 return null;
215 }
216
217 public void put(String namingIdentifier, Object obj) {
218 }
219
220 public void clear() {
221 }
222
223 public void remove(String namingIdentifier) {
224 }
225 }
226
227 public IIdentifierParser newIdentifier(String str, Properties props) throws InvalidIdentifierException {
228 return new DefaultIdentifierParser(str, props);
229 }
230
231 // See the version of this method declared in ILocator.
232 public Object getObject(String namingIdentifier) throws ServiceLocatorException {
233 return getObject(namingIdentifier, (ServiceLocatorOptions)null);
234 }
235
236 // See the version of this method declared in ILocator.
237 public synchronized void removeFromCache(String namingIdentifier) {
238 getCache().remove(namingIdentifier);
239 }
240
241 // See the version of this method declared in ILocator.
242 public synchronized void clearCache() {
243 getCache().clear();
244 }
245
246 // See the version of this method declared in ILocator.
247 public synchronized Object getObject(String namingIdentifier, Class c) throws ServiceLocatorException {
248 return getObject( namingIdentifier, new ServiceLocatorOptions().setCastTo(c) );
249 }
250
251 // See the version of this method declared in ILocator.
252 public synchronized Object getObject(String namingIdentifier, ServiceLocatorOptions options) throws ServiceLocatorException {
253 boolean dbg = _log.isDebugEnabled();
254 if ( dbg ) {
255 _log.debug( "getObject(namingIdentifier=[" + namingIdentifier + "], options=[" + options + "])" );
256 }
257 options = ServiceLocatorOptions.defaultIfNull(options);
258 Object object = null;
259 boolean noCache = options.noCache;
260 if ( ! noCache ) {
261 object = getCache().get(namingIdentifier);
262 }
263 if ( object == null ) {
264 try {
265 object = lookup( namingIdentifier, options );
266 getCache().put(namingIdentifier, object);
267 }
268 catch( ServiceLocatorException sle ) {
269 throw sle;
270 }
271 catch( Exception e ) {
272 throw new ServiceLocatorException(e);
273 }
274 }
275 return narrow(object, options);
276 }
277
278 // See the version of this method declared in ILocator.
279 public synchronized void setCache(ICache cache) {
280 _cache = cache;
281 }
282
283 // See the version of this method declared in ILocator.
284 public synchronized ICache getCache() {
285 return _cache;
286 }
287
288 // See the version of this method declared in ILocator.
289 public synchronized void setNarrowStrategy(INarrowStrategy ls) {
290 _narrowStrategy = ls;
291 }
292
293 // See the version of this method declared in ILocator.
294 public synchronized INarrowStrategy getNarrowStrategy() {
295 return _narrowStrategy;
296 }
297
298 // See the version of this method declared in ILocator.
299 public synchronized void setLookupStrategy(ILookupStrategy ls) {
300 _lookupStrategy = ls;
301 }
302
303 // See the version of this method declared in ILocator.
304 public synchronized ILookupStrategy getLookupStrategy() {
305 return _lookupStrategy;
306 }
307
308 // See the version of this method declared in ILocator.
309 public ICache newCache() {
310 return new NullCache();
311 }
312
313 // See the version of this method declared in ILocator.
314 public ILookupStrategy newLookupStrategy() {
315 return new DefaultLookupStrategy(this);
316 }
317
318 // See the version of this method declared in ILocator.
319 public INarrowStrategy newNarrowStrategy() {
320 return new DefaultNarrowStrategy();
321 }
322
323 // See the version of this method declared in ILocator.
324 public Object narrow(Object o, ServiceLocatorOptions options) throws ServiceLocatorException {
325 Object object = o;
326 Class castTo = null;
327 options = ServiceLocatorOptions.defaultIfNull(options);
328 if ( options.castTo == null ) {
329 castTo = getDefaultCast();
330 }
331 if ( castTo != null ) {
332 object = narrow(object, castTo);
333 }
334 return object;
335 }
336
337 // See the version of this method declared in ILocator.
338 public Object narrow(Object o, Class c) throws ServiceLocatorException {
339 return getNarrowStrategy().narrow(o, c);
340 }
341
342 /**
343 * Simply calls "<code>getLookupStrategy().lookup(namingIdentifier, options)</code>". If you wish to
344 * change the way lookups are performed, write your own {@link ILocator.ILookupStrategy} and either override
345 * {@link #newLookupStrategy()} to instantiate it, or call the public {@link #setLookupStrategy(ILocator.ILookupStrategy)}
346 * method to replace the existing lookup strategy.
347 */
348 public Object lookup(String namingIdentifier, ServiceLocatorOptions options) throws ServiceLocatorException {
349 return getLookupStrategy().lookup(namingIdentifier, options);
350 }
351
352 // See the version of this method declared in ILocator.
353 public Class getDefaultCast() {
354 return null;
355 }
356
357 private ICache _cache = newCache();
358 private ILookupStrategy _lookupStrategy = newLookupStrategy();
359 private INarrowStrategy _narrowStrategy = newNarrowStrategy();
360 private static Log _log = LogFactory.getLog(Locator.class);
361 }
362