/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* 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
*******************************************************************************/
package org.ebayopensource.turmeric.runtime.sif.impl.internal.config;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceCreationException;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.DomParseUtils;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.MessageProcessorConfigMapper;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.MetadataPropertyConfigHolder;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.OptionList;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.TypeMappingConfigHolder;
import org.ebayopensource.turmeric.runtime.common.impl.internal.utils.ServiceNameUtils;
import org.ebayopensource.turmeric.runtime.common.monitoring.MonitoringLevel;
import org.ebayopensource.turmeric.runtime.common.pipeline.TransportOptions;
import org.ebayopensource.turmeric.runtime.common.types.SOAConstants;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import com.ebay.kernel.variable.VariableResolver;
// Copy non-null source data into the destination holder.
// The very first time the ServiceInvokerOptions is initialized,
public class ClientConfigMapper {
// Called to store the shared data between a group definition and an instance definition. This shared data is represented by
// clientInstanceConfig. When called for an instance definition, there is extra info in "clientConfig" (the parent element) that
// we need to also store.
public static void map(String adminName, String filename, Element clientConfig, Element clientInstanceConfig, ClientConfigHolder dst) throws ServiceCreationException {
if (clientConfig != null) {
mapClientConfig(adminName, filename, clientConfig, dst);
}
if (clientInstanceConfig == null) {
return;
// we allow client instance config to be absent - this would be a trivial config with no overridden parameter values.
}
NodeList customSerializers = null;
Element invocationOptions = DomParseUtils.getSingleElement(filename, clientInstanceConfig, "invocation-options");
if (invocationOptions != null) {
mapInvocationOptions(filename, invocationOptions, dst);
customSerializers = DomParseUtils.getImmediateChildrenByTagName(invocationOptions, "custom-serializers");
}
Element cachePolicyConfig = DomParseUtils.getSingleElement(filename, clientInstanceConfig, "cache-policy");
if (cachePolicyConfig != null) {
mapCachePolicyConfig(filename, cachePolicyConfig, dst);
}
Element pipelineConfig = DomParseUtils.getSingleElement(filename, clientInstanceConfig, "pipeline-config");
NodeList protocolProcessors = DomParseUtils.getImmediateChildrenByTagName(clientInstanceConfig, "protocol-processor");
NodeList transports = DomParseUtils.getImmediateChildrenByTagName(clientInstanceConfig, "transport");
Element dataBindingConfig = DomParseUtils.getSingleElement(filename, clientInstanceConfig, "data-binding-config");
OptionList requestHeaderMappingOptions = DomParseUtils.getOptionList(filename, clientInstanceConfig, "request-header-mapping-options");
if (requestHeaderMappingOptions != null) {
dst.setRequestHeaderMappingOptions(requestHeaderMappingOptions);
}
OptionList responseHeaderMappingOptions = DomParseUtils.getOptionList(filename, clientInstanceConfig, "response-header-mapping-options");
if (responseHeaderMappingOptions != null) {
dst.setResponseHeaderMappingOptions(responseHeaderMappingOptions);
}
MessageProcessorConfigMapper.map(filename, customSerializers, null, dst.getErrorDataProviderClass(), pipelineConfig, protocolProcessors, transports, dataBindingConfig, dst.getMessageProcessorConfig());
}
private static void mapClientConfig(String adminName, String filename, Element clientConfig, ClientConfigHolder dst)
throws ServiceCreationException {
MetadataPropertyConfigHolder metadataProps = ClientConfigManager.getInstance().getMetadataPropertyConfigHolder(adminName);
dst.setMetaData(metadataProps);
String serviceName;
if (metadataProps.getSmpVersion() >= 1.1d) {
StringBuilder serviceqname = new StringBuilder();
serviceqname.append('{').append(metadataProps.getServiceNamespace()).append('}');
serviceqname.append(metadataProps.getServiceName());
serviceName = serviceqname.toString();
}
else {
serviceName = clientConfig.getAttribute("service-name");
if(serviceName.isEmpty())
serviceName = metadataProps.getServiceName();
}
QName serviceQname = ServiceNameUtils.normalizeQName(QName.valueOf(serviceName));
dst.setServiceQName(serviceQname);
List<String> locations = new ArrayList<String>();
NodeList locs = DomParseUtils.getImmediateChildrenByTagName(clientConfig, "service-location");
if (locs != null && locs.getLength()>0) {
for(int i=0; i<locs.getLength(); ++i){
Element e = (Element)locs.item(i);
locations.add(e.getTextContent());
}
dst.setServiceLocations(locations);
}
Element locationMappings = DomParseUtils.getSingleElement(filename, clientConfig, "service-location-mappings");
if (locationMappings != null) {
mapLocationMappings(filename, locationMappings, dst);
}
String serviceIntfcClassName = DomParseUtils.getElementText(filename, clientConfig, "service-interface-class-name");
if (serviceIntfcClassName != null) {
dst.setServiceInterfaceClassName(serviceIntfcClassName);
}
String wsdlLocation = DomParseUtils.getElementText(filename, clientConfig, "wsdl-location");
if (wsdlLocation != null) {
dst.setWsdlLocation(wsdlLocation);
}
}
private static void mapLocationMappings(String filename, Element locationMappings, ClientConfigHolder dstConfig) throws ServiceCreationException {
if (locationMappings == null) {
return;
}
NodeList locationMappingList = DomParseUtils.getImmediateChildrenByTagName(locationMappings, "service-location-mapping");
Map<String, String> locationMap = new HashMap<String, String>(locationMappingList.getLength());
for (int i = 0; i < locationMappingList.getLength(); i++) {
Element element = (Element)locationMappingList.item(i);
String env = DomParseUtils.getElementText(filename, element, "name", true);
if (env == null || env.length() == 0) {
DomParseUtils.throwError(filename, "Missing required value on element 'name'" );
}
String url = DomParseUtils.getElementText(filename, element, "url", true);
if (url == null || url.length() == 0) {
DomParseUtils.throwError(filename, "Missing required value on element 'url'" );
}
try {
// Invoke the variableResolver as done in the ClientServiceDescFactory.createDesc()
url = VariableResolver.processString(url);
new URL(url);
} catch (MalformedURLException e) {
DomParseUtils.throwError(filename, "Invalid URL: " + url + " String specified for " + env);
}
locationMap.put(env, url);
}
if (locationMap.size() > 0)
dstConfig.setServiceLocationMap(locationMap);
}
private static void mapInvocationOptions(String filename, Element invocationOptions, ClientConfigHolder dstConfig) throws ServiceCreationException {
if (invocationOptions == null) {
return;
}
Element preferredTransport = DomParseUtils.getSingleElement(filename, invocationOptions, "preferred-transport");
if (preferredTransport != null) {
mapPreferredTransport(filename, preferredTransport, dstConfig);
}
Element g11nOptions = DomParseUtils.getSingleElement(filename, invocationOptions, "G11N-options");
if (g11nOptions != null) {
mapG11NOptions(filename, g11nOptions, dstConfig);
}
String useServiceVersion = DomParseUtils.getElementText(filename, invocationOptions, "use-service-version");
if (useServiceVersion != null) {
dstConfig.setServiceVersion(useServiceVersion);
}
String monitoringLevelStr = DomParseUtils.getElementText(filename, invocationOptions, "monitoring-level");
if (monitoringLevelStr != null) {
MonitoringLevel level = DomParseUtils.mapMonitoringLevel(filename, monitoringLevelStr);
dstConfig.setMonitoringLevel(level);
}
String invocationUseCase = DomParseUtils.getElementText(filename, invocationOptions, "invocation-use-case");
if (invocationUseCase != null) {
dstConfig.setInvocationUseCase(invocationUseCase);
}
String consumerId = DomParseUtils.getElementText(filename, invocationOptions, "consumer-id");
if (consumerId != null && !consumerId.isEmpty()) {
dstConfig.setConsumerId(consumerId);
// Also setting the use-case to the consumerId, as this supersedes the other
dstConfig.setInvocationUseCase(SOAConstants.APPNAME_PREFIX + consumerId);
}
String requestDataBinding = DomParseUtils.getElementText(filename, invocationOptions, "request-data-binding");
if (requestDataBinding != null) {
dstConfig.setRequestDataBinding(requestDataBinding);
}
String responseDataBinding = DomParseUtils.getElementText(filename, invocationOptions, "response-data-binding");
if (responseDataBinding != null) {
dstConfig.setResponseDataBinding(responseDataBinding);
}
String messageProtocol = DomParseUtils.getElementText(filename, invocationOptions, "message-protocol");
if (messageProtocol != null) {
dstConfig.setMessageProtocol(messageProtocol);
}
String responseTransport = DomParseUtils.getElementText(filename, invocationOptions, "response-transport");
if (responseTransport != null) {
dstConfig.setResponseTransport(responseTransport);
}
Element retryOptions = DomParseUtils.getSingleElement(filename, invocationOptions, "retry-options");
if (retryOptions != null) {
mapRetryOptions(filename, retryOptions, dstConfig);
}
String customErrorResponseAdapter = DomParseUtils.getElementText(filename, invocationOptions, "custom-error-response-adapter");
if (customErrorResponseAdapter != null) {
dstConfig.setCustomErrorResponseAdapter(customErrorResponseAdapter);
}
String errorDataProviderClass = DomParseUtils.getElementText(filename, invocationOptions, "error-data-provider-class-name");
if (errorDataProviderClass != null) {
dstConfig.setErrorDataProviderClass(errorDataProviderClass);
}
Element markdownOptions = DomParseUtils.getSingleElement(filename, invocationOptions, "markdown-options");
if (markdownOptions != null) {
mapMarkdownOptions(filename, markdownOptions, dstConfig);
}
Element useHttpGet = DomParseUtils.getSingleElement(filename, invocationOptions, "use-rest");
if (useHttpGet != null) {
String useHttpGetStr = DomParseUtils.getText(useHttpGet);
if (useHttpGetStr != null && !useHttpGetStr.equalsIgnoreCase("false")) {
dstConfig.setUseREST(Boolean.TRUE);
} else {
dstConfig.setUseREST(Boolean.FALSE);
}
Integer maxHttpGetUrlByteLength = DomParseUtils.getAttributeInteger(filename, useHttpGet, "max-url-byte-length");
if (maxHttpGetUrlByteLength != null) {
dstConfig.setMaxURLLengthForREST(maxHttpGetUrlByteLength);
}
}
//
String urlPathInfo = DomParseUtils.getElementText(filename, invocationOptions, "url-path-info");
if (urlPathInfo != null) {
dstConfig.setUrlPathInfo(urlPathInfo);
}
}
private static void mapCachePolicyConfig(String filename,
Element cachePolicyConfig, ClientConfigHolder dstConfig) throws ServiceCreationException {
if (cachePolicyConfig == null) {
return;
}
String cacheProviderClass = DomParseUtils.getElementText(filename, cachePolicyConfig, "cache-provider-class-name", true);
if (cacheProviderClass != null && !cacheProviderClass.isEmpty()) {
dstConfig.setCacheProviderClass(cacheProviderClass);
}
Boolean disableCacheOnLocal = DomParseUtils.getElementBoolean(filename, cachePolicyConfig, "disable-cache-on-local");
if (disableCacheOnLocal != null)
dstConfig.setCacheDisabledOnLocal(disableCacheOnLocal);
Boolean skipCacheOnError = DomParseUtils.getElementBoolean(filename, cachePolicyConfig, "skip-cache-on-error");
if (skipCacheOnError != null)
dstConfig.setSkipCacheOnError(skipCacheOnError);
}
private static void mapRetryOptions(String filename, Element retryOptions, ClientConfigHolder dstConfig) throws ServiceCreationException {
Integer appLevelNumRetries = DomParseUtils.getElementInteger(filename, retryOptions, "app-level-num-retries");
if (appLevelNumRetries != null) {
dstConfig.setAppLevelNumRetries(appLevelNumRetries);
}
String appLevelRetryHandler = DomParseUtils.getElementText(filename, retryOptions, "app-level-retry-handler");
if (appLevelRetryHandler != null) {
dstConfig.setRetryHandlerClass(appLevelRetryHandler);
}
List<String> httpRetryCodes = DomParseUtils.getStringList(filename, retryOptions, "retry-transport-status-code");
if (httpRetryCodes != null) {
Set<String> outCodes = new HashSet<String>(httpRetryCodes);
dstConfig.setRetryTransportStatusCodes(outCodes);
}
List<String> exceptionRetryClasses = DomParseUtils.getStringList(filename, retryOptions, "retry-exception-class");
if (exceptionRetryClasses != null) {
Set<String> outClasses = new HashSet<String>(exceptionRetryClasses);
dstConfig.setRetryExceptionClasses(outClasses);
}
List<String> retryErrorIds = DomParseUtils.getStringList(filename, retryOptions, "retry-error-id");
if (retryErrorIds != null) {
Set<String> outErrorIds = new HashSet<String>(retryErrorIds);
dstConfig.setRetryErrorIds(outErrorIds);
}
}
private static void mapMarkdownOptions(String filename, Element markdownOptions, ClientConfigHolder dstConfig) throws ServiceCreationException {
Boolean enabled = DomParseUtils.getElementBoolean(filename, markdownOptions, "enable-auto-markdown");
if (enabled != null) {
dstConfig.setMarkdownEnabled(enabled);
}
Integer errCountThreshold = DomParseUtils.getElementInteger(filename, markdownOptions, "error-count-threshold");
if (errCountThreshold != null) {
dstConfig.setMarkdownErrCountThreshold(errCountThreshold);
}
String stateFactory = DomParseUtils.getElementText(filename, markdownOptions, "markdown-state-factory");
if (stateFactory != null) {
dstConfig.setMarkdownStateFactoryClass(stateFactory);
}
List<String> httpCodes = DomParseUtils.getStringList(filename, markdownOptions, "transport-status-code");
if (httpCodes != null) {
Set<String> outCodes = new HashSet<String>(httpCodes);
dstConfig.setMarkdownTransportStatusCodes(outCodes);
}
List<String> exceptionClasses = DomParseUtils.getStringList(filename, markdownOptions, "exception-class");
if (exceptionClasses != null) {
Set<String> outClasses = new HashSet<String>(exceptionClasses);
dstConfig.setMarkdownExceptionClasses(outClasses);
}
List<String> errorIds = DomParseUtils.getStringList(filename, markdownOptions, "error-id");
if (errorIds != null) {
Set<String> outErrorIds = new HashSet<String>(errorIds);
dstConfig.setMarkdownErrorIds(outErrorIds);
}
}
private static void mapPreferredTransport(String filename, Element preferredTransport, ClientConfigHolder dstConfig) throws ServiceCreationException {
String name = preferredTransport.getAttribute("name");
if (name != null) {
dstConfig.setPreferredTransport(name.toUpperCase()); // always store transport names in upper case
}
Element overrideOptions = DomParseUtils.getSingleElement(filename, preferredTransport, "override-options");
if (overrideOptions != null) {
TransportOptions outOptions = DomParseUtils.mapTransportOptions(filename, overrideOptions);
dstConfig.setTransportOverrideOptions(outOptions);
}
Map<String, String> overrideHeaderOptionsMap = dstConfig.getTransportOverrideHeaderOptions();
OptionList overrideHeaderOptions = DomParseUtils.getOptionList(filename, preferredTransport, "override-header-options");
DomParseUtils.storeNVListToHashMap(filename, overrideHeaderOptions, overrideHeaderOptionsMap);
}
private static void mapG11NOptions(String filename, Element g11nOptions, ClientConfigHolder dstConfig) throws ServiceCreationException {
String preferredEncoding = DomParseUtils.getElementText(filename, g11nOptions, "preferred-encoding");
if (preferredEncoding != null) {
dstConfig.setPreferredEncoding(preferredEncoding);
}
String preferredLocale = DomParseUtils.getElementText(filename, g11nOptions, "preferred-locale");
if (preferredLocale != null) {
dstConfig.setPreferredLocale(preferredLocale);
}
String preferredGlobalId = DomParseUtils.getElementText(filename, g11nOptions, "preferred-global-id");
if (preferredGlobalId != null) {
dstConfig.setPreferredGlobalId(preferredGlobalId);
}
}
public static ClientConfigHolder applyConfigs(String adminName, String clientName, String envName,String configFilename,
String groupFilename, Element clientGroup, Element clientConfig) throws ServiceCreationException
{
ClientConfigHolder holder = new ClientConfigHolder(adminName, clientName,envName);
holder.setConfigFilename(configFilename);
holder.setGroupFilename(groupFilename);
if (clientGroup != null) { // If the instance config has referenced a group, get the group's instance data - same type as client-instance-config
Element clientInstanceInGroup = DomParseUtils.getSingleElement(groupFilename, clientGroup, "client-config");
map(adminName, groupFilename, null, clientInstanceInGroup, holder);
}
if (clientConfig != null) {
Element clientInstance = DomParseUtils.getSingleElement(groupFilename, clientConfig, "client-instance-config");
map(adminName, configFilename, clientConfig, clientInstance, holder);
}
return holder;
}
public static ClientConfigHolder getConfigFromBaseConfig(
ClientConfigHolder baseConfig, String adminName, String clientName,
String envName, QName svcQName,
TypeMappingConfigHolder typeMappingsCfg) {
return new ClientConfigHolder(baseConfig, adminName, clientName,
envName, svcQName, null, null, typeMappingsCfg, null, null,
null, null, null, null);
}
}