/* * Copyright 2014 JBoss Inc * * Licensed 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 io.apiman.gateway.platforms.war; import io.apiman.common.config.ConfigFactory; import io.apiman.common.logging.DefaultDelegateFactory; import io.apiman.common.logging.IDelegateFactory; import io.apiman.common.plugin.Plugin; import io.apiman.common.plugin.PluginClassLoader; import io.apiman.common.plugin.PluginCoordinates; import io.apiman.common.util.ReflectionUtils; import io.apiman.common.util.crypt.IDataEncrypter; import io.apiman.gateway.engine.EngineConfigTuple; import io.apiman.gateway.engine.GatewayConfigProperties; import io.apiman.gateway.engine.IApiRequestPathParser; import io.apiman.gateway.engine.IComponent; import io.apiman.gateway.engine.IConnectorFactory; import io.apiman.gateway.engine.IEngineConfig; import io.apiman.gateway.engine.IGatewayInitializer; import io.apiman.gateway.engine.IMetrics; import io.apiman.gateway.engine.IPluginRegistry; import io.apiman.gateway.engine.IPolicyErrorWriter; import io.apiman.gateway.engine.IPolicyFailureWriter; import io.apiman.gateway.engine.IRegistry; import io.apiman.gateway.engine.async.IAsyncResult; import io.apiman.gateway.engine.impl.DefaultPolicyErrorWriter; import io.apiman.gateway.engine.impl.DefaultPolicyFailureWriter; import io.apiman.gateway.engine.impl.DefaultRequestPathParser; import io.apiman.gateway.engine.policy.IPolicyFactory; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.apache.commons.configuration.Configuration; /** * Global access to configuration information. * * @author eric.wittmann@redhat.com */ public class WarEngineConfig implements IEngineConfig { public static final Configuration config; static { config = ConfigFactory.createConfig(); } /** * Constructor. */ public WarEngineConfig() { } /** * @return the configuration */ public Configuration getConfig() { return config; } /** * Returns the given configuration property name or the provided default * value if not found. * @param propertyName the property name * @param defaultValue the default value * @return the config property */ public String getConfigProperty(String propertyName, String defaultValue) { return getConfig().getString(propertyName, defaultValue); } /** * @see io.apiman.gateway.engine.IEngineConfig#getRegistryClass(io.apiman.gateway.engine.IPluginRegistry) */ @Override public Class<? extends IRegistry> getRegistryClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.REGISTRY_CLASS, IRegistry.class, pluginRegistry); } /** * @return all properties to be passed to the registry */ @Override public Map<String, String> getRegistryConfig() { return getConfigMap(GatewayConfigProperties.REGISTRY_CLASS); } /** * @return the class to use as the {@link IPluginRegistry} */ @Override @SuppressWarnings("unchecked") public Class<IPluginRegistry> getPluginRegistryClass() { return (Class<IPluginRegistry>) loadConfigClass(GatewayConfigProperties.PLUGIN_REGISTRY_CLASS, IPluginRegistry.class, null); } /** * @return all properties to be passed to the registry */ @Override public Map<String, String> getPluginRegistryConfig() { Map<String, String> configMap = getConfigMap(GatewayConfigProperties.PLUGIN_REGISTRY_CLASS); String pluginsDirOverride = System.getProperty(GatewayConfigProperties.PLUGIN_REGISTRY_CLASS + ".pluginsDir"); //$NON-NLS-1$ if (pluginsDirOverride != null) { configMap.put("pluginsDir", pluginsDirOverride); //$NON-NLS-1$ } return configMap; } /** * @see io.apiman.gateway.engine.IEngineConfig#getConnectorFactoryClass(io.apiman.gateway.engine.IPluginRegistry) */ @Override public Class<? extends IConnectorFactory> getConnectorFactoryClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.CONNECTOR_FACTORY_CLASS, IConnectorFactory.class, pluginRegistry); } /** * @return all properties to be passed to the factory */ @Override public Map<String, String> getConnectorFactoryConfig() { return getConfigMap(GatewayConfigProperties.CONNECTOR_FACTORY_CLASS); } /** * @see io.apiman.gateway.engine.IEngineConfig#getPolicyFactoryClass(io.apiman.gateway.engine.IPluginRegistry) */ @Override public Class<? extends IPolicyFactory> getPolicyFactoryClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.POLICY_FACTORY_CLASS, IPolicyFactory.class, pluginRegistry); } /** * @return all properties to be passed to the factory */ @Override public Map<String, String> getPolicyFactoryConfig() { return getConfigMap(GatewayConfigProperties.POLICY_FACTORY_CLASS); } /** * @see io.apiman.gateway.engine.IEngineConfig#getMetricsClass(io.apiman.gateway.engine.IPluginRegistry) */ @Override public Class<? extends IMetrics> getMetricsClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.METRICS_CLASS, IMetrics.class, pluginRegistry); } /** * @return all properties to be passed to the factory */ @Override public Map<String, String> getMetricsConfig() { return getConfigMap(GatewayConfigProperties.METRICS_CLASS); } /** * @see io.apiman.gateway.engine.IEngineConfig#getComponentClass(java.lang.Class, io.apiman.gateway.engine.IPluginRegistry) */ @Override public <T extends IComponent> Class<? extends T> getComponentClass(Class<? extends T> componentType, IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.COMPONENT_PREFIX + componentType.getSimpleName(), componentType, pluginRegistry); } /** * @return all properties to be passed to the factory */ @Override public <T extends IComponent> Map<String, String> getComponentConfig(Class<T> componentType) { return getConfigMap(GatewayConfigProperties.COMPONENT_PREFIX + componentType.getSimpleName()); } /** * @see io.apiman.gateway.engine.IEngineConfig#getDataEncrypterClass(io.apiman.gateway.engine.IPluginRegistry) */ @Override public Class<? extends IDataEncrypter> getDataEncrypterClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.DATA_ENCRYPTER_TYPE, IDataEncrypter.class, pluginRegistry); } /** * @see io.apiman.gateway.engine.IEngineConfig#getDataEncrypterConfig() */ @Override public Map<String, String> getDataEncrypterConfig() { return getConfigMap("apiman.encrypter"); //$NON-NLS-1$ } @Override @SuppressWarnings("unchecked") public Class<IPolicyFailureWriter> getPolicyFailureWriterClass(IPluginRegistry pluginRegistry) { return (Class<IPolicyFailureWriter>) loadConfigClass(GatewayConfigProperties.FAILURE_WRITER_CLASS, IPolicyFailureWriter.class, pluginRegistry, DefaultPolicyFailureWriter.class); } @Override public Map<String, String> getPolicyFailureWriterConfig() { return getConfigMap(GatewayConfigProperties.FAILURE_WRITER_CLASS); } @Override @SuppressWarnings("unchecked") public Class<IPolicyErrorWriter> getPolicyErrorWriterClass(IPluginRegistry pluginRegistry) { return (Class<IPolicyErrorWriter>) loadConfigClass(GatewayConfigProperties.ERROR_WRITER_CLASS, IPolicyErrorWriter.class, pluginRegistry, DefaultPolicyErrorWriter.class); } @Override public Map<String, String> getPolicyErrorWriterConfig() { return getConfigMap(GatewayConfigProperties.ERROR_WRITER_CLASS); } @Override public Class<? extends IDelegateFactory> getLoggerFactoryClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.LOGGER_FACTORY_CLASS, IDelegateFactory.class, pluginRegistry, DefaultDelegateFactory.class); } @Override public Map<String, String> getLoggerFactoryConfig() { return getConfigMap(GatewayConfigProperties.LOGGER_FACTORY_CLASS); } @Override public Class<? extends IApiRequestPathParser> getApiRequestPathParserClass(IPluginRegistry pluginRegistry) { return loadConfigClass(GatewayConfigProperties.REQUEST_PARSER_CLASS, IApiRequestPathParser.class, pluginRegistry, DefaultRequestPathParser.class); } @Override public Map<String, String> getApiRequestPathParserConfig() { return getConfigMap(GatewayConfigProperties.REQUEST_PARSER_CLASS); } /** * @see io.apiman.gateway.engine.IEngineConfig#getGatewayInitializers(io.apiman.gateway.engine.IPluginRegistry) */ @Override public List<EngineConfigTuple<? extends IGatewayInitializer>> getGatewayInitializers( IPluginRegistry pluginRegistry) { List<EngineConfigTuple<? extends IGatewayInitializer>> rval = new ArrayList<>(); String initializerIds = getConfig().getString(GatewayConfigProperties.INITIALIZERS); if (initializerIds != null) { for (String initializerId : initializerIds.split(",")) { //$NON-NLS-1$ String initializerClassProp = GatewayConfigProperties.INITIALIZERS + "." + initializerId; //$NON-NLS-1$ Class<? extends IGatewayInitializer> initializerClass = loadConfigClass(initializerClassProp, IGatewayInitializer.class, pluginRegistry); Map<String, String> configMap = getConfigMap(initializerClassProp); rval.add(new EngineConfigTuple<>(initializerClass, configMap)); } } return rval; } /** * @return a loaded class */ private <T> Class<? extends T> loadConfigClass(String property, Class<T> type, IPluginRegistry pluginRegistry) { Class<? extends T> rval = loadConfigClass(property, type, pluginRegistry, null); if (rval == null) { throw new RuntimeException("No " + type.getSimpleName() + " class configured."); //$NON-NLS-1$ //$NON-NLS-2$ } return rval; } /** * Load a config class */ @SuppressWarnings("unchecked") private <T> Class<? extends T> loadConfigClass(String property, Class<T> type, IPluginRegistry pluginRegistry, Class<? extends T> defaultClass) { String componentSpec = getConfig().getString(property); if (componentSpec == null) { return defaultClass; } try { if (componentSpec.startsWith("class:")) { //$NON-NLS-1$ Class<?> c = ReflectionUtils.loadClass(componentSpec.substring("class:".length())); //$NON-NLS-1$ return (Class<T>) c; } else if (componentSpec.startsWith("plugin:")) { //$NON-NLS-1$ PluginCoordinates coordinates = PluginCoordinates.fromPolicySpec(componentSpec); if (coordinates == null) { throw new IllegalArgumentException("Invalid plugin component spec: " + componentSpec); //$NON-NLS-1$ } int ssidx = componentSpec.indexOf('/'); if (ssidx == -1) { throw new IllegalArgumentException("Invalid plugin component spec: " + componentSpec); //$NON-NLS-1$ } String classname = componentSpec.substring(ssidx + 1); Future<IAsyncResult<Plugin>> pluginF = pluginRegistry.loadPlugin(coordinates, null); IAsyncResult<Plugin> pluginR = pluginF.get(); if (pluginR.isError()) { throw new RuntimeException(pluginR.getError()); } Plugin plugin = pluginR.getResult(); PluginClassLoader classLoader = plugin.getLoader(); Class<?> class1 = classLoader.loadClass(classname); return (Class<T>) class1; } else { Class<?> c = ReflectionUtils.loadClass(componentSpec); return (Class<T>) c; } } catch (ClassNotFoundException | InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } /** * Gets all properties in the engine configuration that are prefixed * with the given prefix. * @param prefix the prefix * @return all prefixed properties */ private Map<String, String> getConfigMap(String prefix) { Map<String, String> rval = new HashMap<>(); Iterator<?> keys = config.getKeys(prefix); while (keys.hasNext()) { String key = String.valueOf(keys.next()); if (key.equals(prefix)) { continue; } String shortKey = key.substring(prefix.length() + 1); rval.put(shortKey, config.getString(key)); } return rval; } }