/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package javax.naming.ldap;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.NamingException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import org.apache.harmony.jndi.internal.EnvironmentReader;
import org.apache.harmony.jndi.internal.nls.Messages;
/**
* This abstract class is used for factories which create controls as used in
* LDAPv3. These factories are used by service providers to obtain control
* instances when they receive a response control.
*
* @see Control
*/
public abstract class ControlFactory {
/**
* Constructs a <code>ControlFactory</code> instance with no parameters.
*/
protected ControlFactory() {
super();
}
/**
* Uses this control factory to create a particular type of <code>Control
* </code>
* based on the supplied control. It is likely that the supplied control
* contains data encoded in BER format as received from an LDAP server.
* Returns <code>null</code> if the factory cannot create a
* <code>Control</code> else it returns the type of <code>Control</code>
* created by the factory.
*
*
* @param c
* the supplied control
* @throws NamingException
* If an error is encountered.
* @return the control
*/
public abstract Control getControlInstance(Control c)
throws NamingException;
/**
* Creates a particular type of control based on the supplied control c. It
* is likely that the supplied control contains data encoded in BER format
* as received from an LDAP server.
* <p>
* This method tries the factories in LdapContext.CONTROL_FACTORIES, first
* from the supplied <code>Hashtable</code> then from the resource
* provider files of the supplied <code>Context</code>.
* </p>
* <p>
* It returns the supplied control if no factories are loaded or a control
* cannot be created. Otherwise, a new <code>Control</code> instance is
* returned.
*
* @param c
* the supplied <code>Control</code> instance
* @param ctx
* the supplied <code>Context</code> instance
* @param h
* the supplier JNDI environment properties
* @return the supplied control if no factories are loaded or a control
* cannot be created, otherwise a new <code>Control</code>
* instance
* @throws NamingException
* If an error is encountered.
*/
public static Control getControlInstance(Control c, Context ctx,
Hashtable<?, ?> h) throws NamingException {
// obtain control factories from hashtable and provider resource file
String fnames[] = EnvironmentReader
.getFactoryNamesFromEnvironmentAndProviderResource(h, ctx,
LdapContext.CONTROL_FACTORIES);
for (String element : fnames) {
// new factory instance by its class name
ControlFactory factory = null;
try {
factory = (ControlFactory) classForName(element).newInstance();
} catch (Exception e) {
continue;
}
// try obtaining a Control using the factory
Control control = factory.getControlInstance(c);
// if a Control is obtained successfully, return it
if (null != control) {
return control;
}
}
// all factories failed, return the input argument c
return c;
}
/*
* Use the context class loader or the system class loader to load the
* specified class, in a privileged manner.
*/
private static Class<?> classForName(final String className)
throws ClassNotFoundException {
Class<?> cls = AccessController
.doPrivileged(new PrivilegedAction<Class<?>>() {
public Class<?> run() {
// try thread context class loader first
try {
return Class.forName(className, true, Thread
.currentThread().getContextClassLoader());
} catch (ClassNotFoundException e) {
// Ignored
}
// try system class loader second
try {
return Class.forName(className, true, ClassLoader
.getSystemClassLoader());
} catch (ClassNotFoundException e) {
// Ignored
}
// return null, if fail to load class
return null;
}
});
if (cls == null) {
// jndi.1C=class {0} not found
throw new ClassNotFoundException(Messages.getString(
"jndi.1C", className)); //$NON-NLS-1$
}
return cls;
}
}