/** * 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; } }