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 }