/**
* 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 org.apache.hadoop.gateway.config.impl;
import org.apache.hadoop.gateway.config.ConfigurationAdapter;
import org.apache.hadoop.gateway.config.ConfigurationException;
import org.apache.hadoop.gateway.config.spi.ConfigurationAdapterDescriptor;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.ServiceLoader;
public class ConfigurationAdapterFactory {
private static Map<Class<?>, Class<? extends ConfigurationAdapter>> ADAPTERS = null;
private static synchronized Map<Class<?>, Class<? extends ConfigurationAdapter>> getAdapters() {
if( ADAPTERS == null ) {
loadAdapters();
}
return ADAPTERS;
}
private static void loadAdapters() {
Map<Class<?>, Class<? extends ConfigurationAdapter>> all =
new HashMap<Class<?>, Class<? extends ConfigurationAdapter>>();
ServiceLoader<ConfigurationAdapterDescriptor> loader = ServiceLoader.load( ConfigurationAdapterDescriptor.class );
if( loader != null ) {
Iterator<ConfigurationAdapterDescriptor> i = loader.iterator();
if( i != null ) {
while( i.hasNext() ) {
ConfigurationAdapterDescriptor descriptor = i.next();
Map<Class<?>, Class<? extends ConfigurationAdapter>> add = descriptor.providedConfigurationAdapters();
if( add != null ) {
all.putAll( add );
}
}
}
}
ADAPTERS = Collections.unmodifiableMap( all );
}
public static ConfigurationAdapter get( Object config ) throws ConfigurationException {
if( config == null ) {
throw new NullPointerException( "Configuration adapter instantiation impossible for null config object." );
}
try {
Map<Class<?>, Class<? extends ConfigurationAdapter>> adapters = getAdapters();
Class configType = config.getClass();
Class adapterType = findAdapterTypeForConfigTypeOrParent( adapters, configType );
if( adapterType == null ) {
throw new ConfigurationException( "No configuration adapter found for config type " + configType.getName() );
}
Constructor c = findConstructorForConfigType( adapterType, configType );
if( !c.isAccessible() ) {
c.setAccessible( true );
}
Object adapter = c.newInstance( config );
return ConfigurationAdapter.class.cast( adapter );
} catch( ConfigurationException e ) {
throw e;
} catch( Exception e ) {
throw new ConfigurationException( "Configuration adapter instantiation failed.", e );
}
}
public static Constructor findConstructorForConfigType( Class<?> adapterType, Class<?> configType ) throws NoSuchMethodException {
Constructor constructor = null;
Constructor[] constructors = adapterType.getConstructors();
for( Constructor candidate : constructors ) {
Class<?>[] paramTypes = candidate.getParameterTypes();
if( paramTypes.length == 1 ) {
Class<?> paramType = paramTypes[0];
if( paramType.isAssignableFrom( configType ) ) {
constructor = candidate;
break;
}
}
}
if( constructor == null ) {
throw new NoSuchMethodException( "No constructor for " + adapterType.getName() + " that will accept " + configType.getName() );
}
return constructor;
}
public static Class<? extends ConfigurationAdapter> findAdapterTypeForConfigTypeOrParent(
Map<Class<?>, Class<? extends ConfigurationAdapter>> adapters, Class<?> configType ) {
Class<? extends ConfigurationAdapter> adapterType = null;
while( configType != null ) {
adapterType = findAdapterTypeForConfigType( adapters, configType );
if( adapterType != null ) {
break;
}
configType = configType.getSuperclass();
}
return adapterType;
}
public static Class<? extends ConfigurationAdapter> findAdapterTypeForConfigType(
Map<Class<?>, Class<? extends ConfigurationAdapter>> adapters, Class<?> configType ) {
Class<? extends ConfigurationAdapter> adapterType = adapters.get( configType );
if( adapterType == null ) {
for( Class interfaceType : configType.getInterfaces() ) {
adapterType = findAdapterTypeForConfigTypeOrParent( adapters, interfaceType );
if( adapterType != null ) {
break;
}
}
}
return adapterType;
}
}