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