/*******************************************************************************
* 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.common.impl.internal.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.xml.namespace.QName;
import org.ebayopensource.turmeric.runtime.common.binding.DataBindingDesc;
import org.ebayopensource.turmeric.runtime.common.errors.ErrorDataProvider;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.CommonConfigHolder;
import org.ebayopensource.turmeric.runtime.common.impl.internal.config.MetadataPropertyConfigHolder;
import org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring.SystemMetricDefs;
import org.ebayopensource.turmeric.runtime.common.impl.pipeline.NullProtocolProcessor;
import org.ebayopensource.turmeric.runtime.common.pipeline.Dispatcher;
import org.ebayopensource.turmeric.runtime.common.pipeline.LoggingHandler;
import org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext;
import org.ebayopensource.turmeric.runtime.common.pipeline.Pipeline;
import org.ebayopensource.turmeric.runtime.common.service.HeaderMappingsDesc;
import org.ebayopensource.turmeric.runtime.common.service.ServiceId;
import org.ebayopensource.turmeric.runtime.common.service.ServiceOperationDesc;
import org.ebayopensource.turmeric.runtime.common.service.ServiceTypeMappings;
/**
* Service Description (ServiceDesc) is an object loaded at service initialization
* (startup time or lazy init). ServiceDesc contains all pre-built data
* structures necessary for the service execution. Most of the SOA framework and extension implementation
* will not need direct access to configuration (e.g. Common/Client/ServiceConfigHolder), since the most relevant
* information is stored and accessible in ServiceDesc as fully validated and processed information.
* ServiceDesc has two subclasses: ClientServiceDesc and ServerServiceDesc, which extend the base class in order to
* provide data applicable to client-side or server-side operation only.
*
* ServiceDesc is considered an implementation detail and should generally not be used by service writers or consumers.
* Refer to ServiceContext for a more public representation of the most important client/service configuration and state.
* <UL>
* <LI> Service admin name and fully qualified name
* <LI> Low-level source configuration
* <LI> Reference to service Class Loader
* <LI> List of service operations descriptions (map of name-to-operation)
* <LI> List of service data binding descriptions (map of name-to-binding)
* <LI> ServiceTypeMappings defining mapping of Java and XML type names, namespaces and packages
* <LI> Both Request and Response pipeline instances
* <LI> Request and Response dispatcher instances
* <LI> List of service protocol processors instances (map of name-to-processor)
* <LI> List of service transport instances (map of name-to-transport)
* <LI> List of service logging handler instances
* <LI> Service Interface class pointer
* <LI> Cached metric value aggregators
* <LI> List of request header mappings (map of name-to-name)
* <LI> List of response header mappings (map of name-to-name)
* <UL>
*
* @author ichernyshev
*/
public abstract class ServiceDesc {
private final ServiceId m_id;
private final QName m_serviceQName;
private final CommonConfigHolder m_config;
private final Pipeline m_requestPipeline;
private final Pipeline m_responsePipeline;
private final Dispatcher m_requestDispatcher;
private final Dispatcher m_responseDispatcher;
private final Map<String,ServiceOperationDesc> m_operations;
private final Map<String,ProtocolProcessorDesc> m_protocols;
private final Map<String,DataBindingDesc> m_bindings;
private final ServiceTypeMappings m_typeMappings;
private final ClassLoader m_classLoader;
private final List<LoggingHandler> m_loggingHandlers;
private final Class m_serviceInterfaceClass;
private final ProtocolProcessorDesc m_nullProtocolProcessor;
private final List<String> m_serviceLayers;
private final ServiceMetricHolder m_metrics;
private final HeaderMappingsDesc m_requestHeaderMappings;
private final HeaderMappingsDesc m_responseHeaderMappings;
private final ErrorDataProvider m_errorDataProviderClass;
protected ServiceDesc(ServiceDesc descToCopy, ServiceId id,
QName serviceQName,
CommonConfigHolder config,
Pipeline requestPipeline,
Pipeline responsePipeline,
Dispatcher requestDispatcher,
Dispatcher responseDispatcher,
Map<String,ServiceOperationDesc> operations,
Map<String,ProtocolProcessorDesc> protocols,
Map<String,DataBindingDesc> bindings,
ServiceTypeMappings typeMappings,
ClassLoader classLoader,
List<LoggingHandler> loggingHandlers,
Class serviceInterfaceClass,
List<String> serviceLayers,
HeaderMappingsDesc requestHeaderMappings,
HeaderMappingsDesc responseHeaderMappings,
ErrorDataProvider errorDataProviderClas){
this(
id = id == null ? descToCopy.m_id : id,
serviceQName = serviceQName == null ? descToCopy.m_serviceQName
: serviceQName,
config = config == null ? descToCopy.m_config : config,
requestPipeline = requestPipeline == null ? descToCopy.m_requestPipeline
: requestPipeline,
responsePipeline = responsePipeline == null ? descToCopy.m_responsePipeline
: responsePipeline,
requestDispatcher = requestDispatcher == null ? descToCopy.m_requestDispatcher
: requestDispatcher,
responseDispatcher = responseDispatcher == null ? descToCopy.m_responseDispatcher
: responseDispatcher,
operations = operations == null ? descToCopy.m_operations
: operations,
protocols = protocols == null ? descToCopy.m_protocols
: protocols,
bindings = bindings == null ? descToCopy.m_bindings : bindings,
typeMappings = typeMappings == null ? descToCopy.m_typeMappings
: typeMappings,
classLoader = classLoader == null ? descToCopy.m_classLoader
: classLoader,
loggingHandlers = loggingHandlers == null ? descToCopy.m_loggingHandlers
: loggingHandlers,
serviceInterfaceClass = serviceInterfaceClass == null ? descToCopy.m_serviceInterfaceClass
: serviceInterfaceClass,
serviceLayers = serviceLayers == null ? descToCopy.m_serviceLayers
: serviceLayers,
requestHeaderMappings = requestHeaderMappings == null ? descToCopy.m_requestHeaderMappings
: requestHeaderMappings,
responseHeaderMappings = responseHeaderMappings == null ? descToCopy.m_responseHeaderMappings
: responseHeaderMappings,
errorDataProviderClas = errorDataProviderClas == null ? descToCopy.m_errorDataProviderClass
: errorDataProviderClas);
}
/**
* Constructor. Intended to be called only by the internal subclasses.
*
* @param id
* @param serviceQName
* @param config
* @param requestPipeline
* @param responsePipeline
* @param requestDispatcher
* @param responseDispatcher
* @param operations
* @param protocols
* @param bindings
* @param typeMappings
* @param classLoader
* @param loggingHandlers
* @param serviceInterfaceClass
*/
protected ServiceDesc(ServiceId id,
QName serviceQName,
CommonConfigHolder config,
Pipeline requestPipeline,
Pipeline responsePipeline,
Dispatcher requestDispatcher,
Dispatcher responseDispatcher,
Map<String,ServiceOperationDesc> operations,
Map<String,ProtocolProcessorDesc> protocols,
Map<String,DataBindingDesc> bindings,
ServiceTypeMappings typeMappings,
ClassLoader classLoader,
List<LoggingHandler> loggingHandlers,
Class serviceInterfaceClass,
List<String> serviceLayers,
HeaderMappingsDesc requestHeaderMappings,
HeaderMappingsDesc responseHeaderMappings,
ErrorDataProvider errorDataProviderClass)
{
if (id == null || serviceQName == null ||
requestPipeline == null || responsePipeline == null ||
requestDispatcher == null || responseDispatcher == null ||
protocols == null || bindings == null || operations == null ||
loggingHandlers == null || classLoader == null ||
typeMappings == null)
{
throw new NullPointerException();
}
m_id = id;
m_serviceQName = serviceQName;
m_config = config;
m_requestPipeline = requestPipeline;
m_responsePipeline = responsePipeline;
m_requestDispatcher = requestDispatcher;
m_responseDispatcher = responseDispatcher;
m_operations = operations;
m_protocols = Collections.unmodifiableMap(protocols);
m_bindings = bindings;
m_typeMappings = typeMappings;
m_classLoader = classLoader;
m_loggingHandlers = Collections.unmodifiableList(
new ArrayList<LoggingHandler>(loggingHandlers));
m_serviceInterfaceClass = serviceInterfaceClass;
m_serviceLayers = serviceLayers;
m_nullProtocolProcessor = new ProtocolProcessorDesc("{null}", new NullProtocolProcessor(), null);
((ServiceTypeMappingsImpl)typeMappings).cleanTypeDefsBuilder();
m_metrics = new ServiceMetricHolder(id, null);
m_requestHeaderMappings = requestHeaderMappings;
m_responseHeaderMappings = responseHeaderMappings;
m_errorDataProviderClass = errorDataProviderClass;
}
/**
* Returns the administrative name of the service whose invocation is currently in process for this message context.
* On the client side, the administrative name is the local part of the service qualified name configured in ClientConfig.xml.
* On the server side, the administrative name matches the folder name holding the ServiceConfig.xml file.
* @return the administrative name
*/
public final String getAdminName() {
return m_id.getAdminName();
}
/**
* Returns the fully qualified name of the service which is currently being invoked; clients and services mutually associate
* this value in order to uniquely identify the service to be invoked.
* @return the service qualified name
*/
public final QName getServiceQName() {
return m_serviceQName;
}
/**
* Returns a client/service identifier associated with a local configuration instance. This identifier consists of
* the administrative name of the service being consumed or provided, plus any sub-identification such as the consuming
* client (configuration) instance.
* @return the service identifier
*/
public ServiceId getServiceId() {
return m_id;
}
/**
* Returns true if the configuration reflects the default fallback configuration used in case of error (e.g. if no configuration
* matching the requests's service name can be found).
* @return true if the configuration reflects the default fallback configuration
*/
public final boolean isFallback() {
return (m_config == null);
}
/**
* Throw an exception if there is no underlying configuration, i.e. if any stored configuration reflects the
* default fallback configuration used in case of error.
*/
protected final void checkNotFallback() {
if (m_config == null) {
throw new IllegalStateException(
"This is a fallback ServiceDesc and Config is not available here");
}
}
/**
* Returns a reference to an object representing the low-level source configuration for this client or service.
* @return the configuration reference
*/
public final CommonConfigHolder getConfig() {
checkNotFallback();
return m_config;
}
/**
* Returns a reference to the applicable class loader for the currently executing client or service.
* @return the class loader
*/
public final ClassLoader getClassLoader() {
return m_classLoader;
}
/**
* Returns the current request pipeline instance.
* @return the request pipeline
*/
public final Pipeline getRequestPipeline() {
return m_requestPipeline;
}
/**
* Returns the current response pipeline instance.
* @return the response pipeline
*/
public final Pipeline getResponsePipeline() {
return m_responsePipeline;
}
/**
* Returns the current response pipeline instance.
* @return the response pipeline
*/
public final ErrorDataProvider getErrorDataProviderClass() {
return m_errorDataProviderClass;
}
/**
* Returns the current request dispatcher instance.
* @return the request dispatcher
*/
public final Dispatcher getRequestDispatcher() {
return m_requestDispatcher;
}
/**
* Returns the current response dispatcher instance.
* @return the response dispatcher
*/
public final Dispatcher getResponseDispatcher() {
return m_responseDispatcher;
}
/**
* Returns the current list of logging handlers for the service.
* @return the list of logging handlers
*/
public final List<LoggingHandler> getLoggingHandlers() {
return m_loggingHandlers;
}
/**
* Returns the Class representing the service interface.
* @return the service interface class
*/
public final Class getServiceInterfaceClass() {
checkNotFallback();
return m_serviceInterfaceClass;
}
/**
* Get the configuration, such as request, response, and error message types, associated with a particular operation.
* @param name the name of the operation for which to return configuration
* @return the operation-specific configuration
*/
public final ServiceOperationDesc getOperation(String name) {
return m_operations.get(name);
}
/**
* Get the collection of all configuration associated with each operation for the currently invoked service.
* @return the map of configuration
*/
public final Collection<ServiceOperationDesc> getAllOperations() {
return Collections.unmodifiableCollection(m_operations.values());
}
/**
* Get the protocol processor configuration associated with the specified name.
* @param name the message protocol name (e.g. "SOAP11")
* @return the protocol processor configuration
*/
public final ProtocolProcessorDesc getProtocolProcessor(String name) {
return m_protocols.get(name);
}
/**
* Get the protocol processors
*/
public final Collection<ProtocolProcessorDesc> getAllProtocolProcessors() {
return m_protocols.values();
}
/**
* Get the data binding (serialization) configuration associated with a particular data binding name (e.g. "json").
* @param name the data binding name for which to return configuration
* @return the data binding configuration
*/
public final DataBindingDesc getDataBindingDesc(String name) {
return m_bindings.get(name);
}
/**
* @return the list of service layers
*/
public List<String> getServiceLayerNames() {
return m_serviceLayers;
}
/**
* Returnes the collection of all configuration associated with all data bindings configured for the currently invoked service.
* @return the data bindings
*/
public final Collection<DataBindingDesc> getAllDataBindings() {
return Collections.unmodifiableCollection(m_bindings.values());
}
/**
* Returnes the configuration for the default protocol processor (which takes no action at any pipeline processing stage).
* @return the default ProtocolProcessorDesc
*/
public final ProtocolProcessorDesc getNullProtocolProcessor() {
return m_nullProtocolProcessor;
}
/**
* Returns the collection of all type mapping data (e.g. maps associating XML namespaces to Java packages) for the currently
* invoked service.
* @return the type mappings
*/
public final ServiceTypeMappings getTypeMappings() {
return m_typeMappings;
}
/**
* Updates a given metric, never throws exceptions
*/
public void updateMetric(MessageContext ctx, SystemMetricDefs.SvcLevelMetricDef def, long count) {
if (!isFallback()) {
m_metrics.update(ctx, def, count);
}
}
/**
* @return the Request Header Mappings
*/
public HeaderMappingsDesc getRequestHeaderMappings() {
return m_requestHeaderMappings;
}
/**
* @return the Response Header Mappings
*/
public HeaderMappingsDesc getResponseHeaderMappings() {
return m_responseHeaderMappings;
}
/**
* Returns the Canonical form of the Service if the
* meta data holder has been loaded, serviceQName Otherwise.
* @return String, the canonical service name.
*/
public String getCanonicalServiceName() {
if (m_config != null) {
StringBuilder serviceName = new StringBuilder();
MetadataPropertyConfigHolder metadata = m_config.getMetaData();
if (metadata != null) {
serviceName.append("( ");
String namespace = metadata.getServiceNamespace();
// Pre 2.4 service, get the namespace from serviceQname
if (namespace == null) {
namespace = m_serviceQName.getNamespaceURI();
}
serviceName.append(namespace).append(", ");
serviceName.append(metadata.getServiceName()).append(", ");
serviceName.append(metadata.getVersion()).append(" )");
return serviceName.toString();
}
}
// Handle Fallback ServiceDesc
return m_serviceQName.toString();
}
}