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
026 import java.util.Properties;
027 import java.util.Hashtable;
028
029
030 /**
031 * Abstract Provider base class and factory for accessing berlib specific
032 * Provider implementations and their SPI implementation classes.
033 *
034 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
035 * @version $Revision: 725712 $
036 */
037 public abstract class Provider
038 {
039 /** Default BER Library provider class name */
040 public static final String DEFAULT_PROVIDER = "org.apache.directory.shared.ldap.codec.TwixProvider";
041
042 /** BER Library provider class name property */
043 public static final String BERLIB_PROVIDER = "asn.1.berlib.provider";
044
045 /** The default file searched for on CP to load default provider props. */
046 public static final String BERLIB_PROPFILE = "berlib.properties";
047
048 /** A provider monitor key. */
049 public static final String PROVIDER_MONITOR_KEY = "asn.1.berlib.provider.monitor";
050
051 /** Message to use when using defaults */
052 public static final String USING_DEFAULTS_MSG = "Could not find the ASN.1 berlib provider properties file: "
053 + "berlib.properties.\nFile is not present on the classpath " + "or in $JAVA_HOME/lib:\n\tjava.home = "
054 + System.getProperty( "java.home" ) + "\n\tjava.class.path = " + System.getProperty( "java.class.path" );
055
056 /** Use the no-op monitor by default unless we find something else */
057 private static ProviderMonitor monitor;
058
059 static
060 {
061 findMonitor( System.getProperties() );
062 }
063
064
065 /*
066 * Checks to see if the provider monitor has been set as a system property.
067 * If it has try to instantiate it and use it.
068 */
069 private static void findMonitor( Properties props )
070 {
071 if ( props.containsKey( PROVIDER_MONITOR_KEY ) )
072 {
073 String fqcn = System.getProperties().getProperty( PROVIDER_MONITOR_KEY );
074
075 if ( fqcn != null )
076 {
077 Class<?> mc;
078
079 try
080 {
081 mc = Class.forName( fqcn );
082 monitor = ( ProviderMonitor ) mc.newInstance();
083 }
084 catch ( ClassNotFoundException e )
085 {
086 System.err.println( "provider monitor class " + fqcn + " not found" );
087 }
088 catch ( IllegalAccessException e )
089 {
090 System.err.println( "provider monitor class " + fqcn
091 + " does not expose a public default constructor" );
092 }
093 catch ( InstantiationException e )
094 {
095 System.err.println( "provider monitor class " + fqcn + " failed during instantiation" );
096 }
097 }
098 }
099
100 if ( monitor == null )
101 {
102 monitor = ProviderMonitor.NOOP_MONITOR;
103 }
104 }
105
106 // ------------------------------------------------------------------------
107 // Provider Properties
108 // ------------------------------------------------------------------------
109
110 /** The descriptive string to identify this provider */
111 private final String name;
112
113 /** The Provider's vendor name */
114 private final String vendor;
115
116
117 // ------------------------------------------------------------------------
118 // Constructors
119 // ------------------------------------------------------------------------
120
121 /**
122 * Creates an instance of a Provider.
123 *
124 * @param name
125 * a descriptive name for a provider
126 * @param vendor
127 * the berlib vendor used by the provider
128 */
129 protected Provider( String name, String vendor )
130 {
131 this.name = name;
132 this.vendor = vendor;
133 }
134
135
136 // ------------------------------------------------------------------------
137 // Property Accessor Methods
138 // ------------------------------------------------------------------------
139
140 /**
141 * Gets the descriptive name for this Provider.
142 *
143 * @return the Provider's name.
144 */
145 public final String getName()
146 {
147 return name;
148 }
149
150
151 /**
152 * Gets this Providers vendor name if it was provided.
153 *
154 * @return the vendor name for this provider or the String 'UNKNOWN' if it
155 * is not known.
156 */
157 public final String getVendor()
158 {
159 return vendor;
160 }
161
162
163 /**
164 * Gets the encoder associated with this provider.
165 *
166 * @return the provider's encoder.
167 * @throws ProviderException
168 * if the provider or its encoder cannot be found
169 */
170 public abstract ProviderEncoder getEncoder() throws ProviderException;
171
172
173 /**
174 * Gets the decoder associated with this provider.
175 *
176 * @return the provider's decoder.
177 * @throws ProviderException if the provider or its decoder cannot be found
178 * @param binaryAttributeDetector detects whether or not attributes are binary
179 * @param maxPDUSize the maximum size a PDU can be
180 */
181 public abstract ProviderDecoder getDecoder( BinaryAttributeDetector binaryAttributeDetector,
182 int maxPDUSize )
183 throws ProviderException;
184
185
186 // ------------------------------------------------------------------------
187 // Factory/Environment Methods
188 // ------------------------------------------------------------------------
189
190
191 /**
192 * Gets an instance of the configured Provider. The configured provider is
193 * the classname specified by the <code>asn.1.berlib.provider</code>
194 * property. The property is searched for within berlib.properties files
195 * that are on the java.class.path. If at least one berlib.properties is not
196 * found the default provider is used. The resultant value (default or
197 * otherwise) for the property can be overridden by command line properties.
198 *
199 * @return a singleton instance of the configured ASN.1 BER Library Provider
200 * @throws ProviderException
201 * if the provider cannot be found
202 */
203 public static Provider getProvider() throws ProviderException
204 {
205 return getProvider( getEnvironment() );
206 }
207
208
209 /**
210 * Gets an instance of the Provider specified by the <code>
211 * asn.1.berlib.provider</code>
212 * property value. The property is searched for within properties object
213 * passed in as a parameter for this method only.
214 *
215 * @param env
216 * the environment used to locate the provider
217 * @return a singleton instance of the ASN.1 BER Library Provider
218 * @throws ProviderException
219 * if the provider cannot be found
220 */
221 public static Provider getProvider( Hashtable<Object, Object> env ) throws ProviderException
222 {
223 Provider provider;
224 String className = ( String ) env.get( BERLIB_PROVIDER );
225
226 // --------------------------------------------------------------------
227 // Check for a valid property value
228 // --------------------------------------------------------------------
229 if ( ( className == null ) || className.trim().equals( "" ) )
230 {
231 throw new ProviderException( null, "Could not instantiate provider - environment does not specify "
232 + BERLIB_PROVIDER + " property!" );
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, "Count not find the Provider class " + className );
244 pe.addThrowable( cnfe );
245 throw pe;
246 }
247 catch ( NoSuchMethodException nsme )
248 {
249 ProviderException pe = new ProviderException( null, "Count not invoke the Provider's factory method: "
250 + className + ".getProvider() - it may not exist!" );
251 pe.addThrowable( nsme );
252 throw pe;
253 }
254 catch ( IllegalAccessException iae )
255 {
256 ProviderException pe = new ProviderException( null, "Count not invoke the Provider's factory method: "
257 + className + ".getProvider() - it does seem to be a public method!" );
258 pe.addThrowable( iae );
259 throw pe;
260 }
261 catch ( InvocationTargetException ite )
262 {
263 ProviderException pe = new ProviderException( null, "Call to Provider's factory method: " + className
264 + ".getProvider() threw the following exception:\n" + ite.getTargetException() );
265 pe.addThrowable( ite.getTargetException() );
266 throw pe;
267 }
268
269 return provider;
270 }
271
272
273 /**
274 * Loads the properties for the effective environment. First searches class
275 * path for the default berlib.properties file. If it cannot find the file
276 * on the classpath it loads the defaults in the default berlib.properties
277 * file found in $JAVA_HOME/lib/berlib.properties. If the default file is
278 * not found and no berlib.properties are found on the classpath then the
279 * default provider is used. Once the property is set overriding values are
280 * searched for in the System's properties specified at startup using the
281 * <code>-Dproperty=value</code><i>java</i> command-line arguments.
282 *
283 * @return the environment properties TODO why are we not throwing
284 * ProviderExceptions here?
285 */
286 public static Properties getEnvironment()
287 {
288 // Prop file not on classpath so we complain and use the default!
289 Properties env = new Properties();
290 env.setProperty( BERLIB_PROVIDER, DEFAULT_PROVIDER );
291 monitor.usingDefaults( USING_DEFAULTS_MSG, env );
292 return env;
293 }
294 }