001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 * 019 */ 020 package org.apache.directory.shared.ldap.message.spi; 021 022 023 import java.lang.reflect.InvocationTargetException; 024 import java.lang.reflect.Method; 025 import java.util.Hashtable; 026 import java.util.Properties; 027 028 import org.apache.directory.shared.i18n.I18n; 029 import org.apache.directory.shared.ldap.codec.LdapProvider; 030 031 032 /** 033 * Abstract Provider base class and factory for accessing berlib specific 034 * Provider implementations and their SPI implementation classes. 035 * 036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 037 * @version $Revision: 912436 $ 038 */ 039 public abstract class Provider 040 { 041 /** Default BER Library provider class name */ 042 public static final String DEFAULT_PROVIDER = LdapProvider.class.getName(); 043 044 /** BER Library provider class name property */ 045 public static final String BERLIB_PROVIDER = "asn.1.berlib.provider"; 046 047 /** The default file searched for on CP to load default provider props. */ 048 public static final String BERLIB_PROPFILE = "berlib.properties"; 049 050 /** A provider monitor key. */ 051 public static final String PROVIDER_MONITOR_KEY = "asn.1.berlib.provider.monitor"; 052 053 /** Message to use when using defaults */ 054 public static final String USING_DEFAULTS_MSG = "Could not find the ASN.1 berlib provider properties file: " 055 + "berlib.properties.\nFile is not present on the classpath " + "or in $JAVA_HOME/lib:\n\tjava.home = " 056 + System.getProperty( "java.home" ) + "\n\tjava.class.path = " + System.getProperty( "java.class.path" ); 057 058 /** Use the no-op monitor by default unless we find something else */ 059 private static ProviderMonitor monitor; 060 061 static 062 { 063 findMonitor( System.getProperties() ); 064 } 065 066 067 /* 068 * Checks to see if the provider monitor has been set as a system property. 069 * If it has try to instantiate it and use it. 070 */ 071 private static void findMonitor( Properties props ) 072 { 073 if ( props.containsKey( PROVIDER_MONITOR_KEY ) ) 074 { 075 String fqcn = System.getProperties().getProperty( PROVIDER_MONITOR_KEY ); 076 077 if ( fqcn != null ) 078 { 079 Class<?> mc; 080 081 try 082 { 083 mc = Class.forName( fqcn ); 084 monitor = ( ProviderMonitor ) mc.newInstance(); 085 } 086 catch ( ClassNotFoundException e ) 087 { 088 System.err.println( I18n.err( I18n.ERR_04177, fqcn ) ); 089 } 090 catch ( IllegalAccessException e ) 091 { 092 System.err.println( I18n.err( I18n.ERR_04178, fqcn ) ); 093 } 094 catch ( InstantiationException e ) 095 { 096 System.err.println( I18n.err( I18n.ERR_04179, fqcn ) ); 097 } 098 } 099 } 100 101 if ( monitor == null ) 102 { 103 monitor = ProviderMonitor.NOOP_MONITOR; 104 } 105 } 106 107 // ------------------------------------------------------------------------ 108 // Provider Properties 109 // ------------------------------------------------------------------------ 110 111 /** The descriptive string to identify this provider */ 112 private final String name; 113 114 /** The Provider's vendor name */ 115 private final String vendor; 116 117 118 // ------------------------------------------------------------------------ 119 // Constructors 120 // ------------------------------------------------------------------------ 121 122 /** 123 * Creates an instance of a Provider. 124 * 125 * @param name 126 * a descriptive name for a provider 127 * @param vendor 128 * the berlib vendor used by the provider 129 */ 130 protected Provider( String name, String vendor ) 131 { 132 this.name = name; 133 this.vendor = vendor; 134 } 135 136 137 // ------------------------------------------------------------------------ 138 // Property Accessor Methods 139 // ------------------------------------------------------------------------ 140 141 /** 142 * Gets the descriptive name for this Provider. 143 * 144 * @return the Provider's name. 145 */ 146 public final String getName() 147 { 148 return name; 149 } 150 151 152 /** 153 * Gets this Providers vendor name if it was provided. 154 * 155 * @return the vendor name for this provider or the String 'UNKNOWN' if it 156 * is not known. 157 */ 158 public final String getVendor() 159 { 160 return vendor; 161 } 162 163 164 /** 165 * Gets the encoder associated with this provider. 166 * 167 * @return the provider's encoder. 168 * @throws ProviderException 169 * if the provider or its encoder cannot be found 170 */ 171 public abstract ProviderEncoder getEncoder() throws ProviderException; 172 173 174 /** 175 * Gets the decoder associated with this provider. 176 * 177 * @return the provider's decoder. 178 * @throws ProviderException if the provider or its decoder cannot be found 179 * @param binaryAttributeDetector detects whether or not attributes are binary 180 * @param maxPDUSize the maximum size a PDU can be 181 */ 182 public abstract ProviderDecoder getDecoder( BinaryAttributeDetector binaryAttributeDetector, 183 int maxPDUSize ) 184 throws ProviderException; 185 186 187 // ------------------------------------------------------------------------ 188 // Factory/Environment Methods 189 // ------------------------------------------------------------------------ 190 191 192 /** 193 * Gets an instance of the configured Provider. The configured provider is 194 * the classname specified by the <code>asn.1.berlib.provider</code> 195 * property. The property is searched for within berlib.properties files 196 * that are on the java.class.path. If at least one berlib.properties is not 197 * found the default provider is used. The resultant value (default or 198 * otherwise) for the property can be overridden by command line properties. 199 * 200 * @return a singleton instance of the configured ASN.1 BER Library Provider 201 * @throws ProviderException 202 * if the provider cannot be found 203 */ 204 public static Provider getProvider() throws ProviderException 205 { 206 return getProvider( getEnvironment() ); 207 } 208 209 210 /** 211 * Gets an instance of the Provider specified by the <code> 212 * asn.1.berlib.provider</code> 213 * property value. The property is searched for within properties object 214 * passed in as a parameter for this method only. 215 * 216 * @param env 217 * the environment used to locate the provider 218 * @return a singleton instance of the ASN.1 BER Library Provider 219 * @throws ProviderException 220 * if the provider cannot be found 221 */ 222 public static Provider getProvider( Hashtable<Object, Object> env ) throws ProviderException 223 { 224 Provider provider; 225 String className = ( String ) env.get( BERLIB_PROVIDER ); 226 227 // -------------------------------------------------------------------- 228 // Check for a valid property value 229 // -------------------------------------------------------------------- 230 if ( ( className == null ) || className.trim().equals( "" ) ) 231 { 232 throw new ProviderException( null, I18n.err( I18n.ERR_04180, BERLIB_PROVIDER ) ); 233 } 234 235 try 236 { 237 Class<?> clazz = Class.forName( className ); 238 Method method = clazz.getMethod( "getProvider", (Class[])null ); 239 provider = ( Provider ) method.invoke( null, (Object[])null ); 240 } 241 catch ( ClassNotFoundException cnfe ) 242 { 243 ProviderException pe = new ProviderException( null, I18n.err( I18n.ERR_04181, className ) ); 244 pe.addThrowable( cnfe ); 245 throw pe; 246 } 247 catch ( NoSuchMethodException nsme ) 248 { 249 ProviderException pe = new ProviderException( null, I18n.err( I18n.ERR_04182, className ) ); 250 pe.addThrowable( nsme ); 251 throw pe; 252 } 253 catch ( IllegalAccessException iae ) 254 { 255 ProviderException pe = new ProviderException( null, I18n.err( I18n.ERR_04183, className ) ); 256 pe.addThrowable( iae ); 257 throw pe; 258 } 259 catch ( InvocationTargetException ite ) 260 { 261 ProviderException pe = new ProviderException( null, I18n.err( I18n.ERR_04184, className, ite.getTargetException() ) ); 262 pe.addThrowable( ite.getTargetException() ); 263 throw pe; 264 } 265 266 return provider; 267 } 268 269 270 /** 271 * Loads the properties for the effective environment. First searches class 272 * path for the default berlib.properties file. If it cannot find the file 273 * on the classpath it loads the defaults in the default berlib.properties 274 * file found in $JAVA_HOME/lib/berlib.properties. If the default file is 275 * not found and no berlib.properties are found on the classpath then the 276 * default provider is used. Once the property is set overriding values are 277 * searched for in the System's properties specified at startup using the 278 * <code>-Dproperty=value</code><i>java</i> command-line arguments. 279 * 280 * @return the environment properties TODO why are we not throwing 281 * ProviderExceptions here? 282 */ 283 public static Properties getEnvironment() 284 { 285 // Prop file not on classpath so we complain and use the default! 286 Properties env = new Properties(); 287 env.setProperty( BERLIB_PROVIDER, DEFAULT_PROVIDER ); 288 monitor.usingDefaults( USING_DEFAULTS_MSG, env ); 289 return env; 290 } 291 }