/*******************************************************************************
* 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
*******************************************************************************/
//B''H
/**
* Change Activity:
*
* Reason Name Date Description
* ----------------------------------------------------------------------------
* SOA 2.3 pkaliyamurthy 03/08/2009 Better System Error Classification.
*
*/
package org.ebayopensource.turmeric.runtime.common.impl.internal.pipeline;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.namespace.QName;
import javax.xml.ws.AsyncHandler;
import org.ebayopensource.turmeric.runtime.binding.ITypeConversionContext;
import org.ebayopensource.turmeric.runtime.binding.exception.DataValidationErrorException;
import org.ebayopensource.turmeric.runtime.binding.exception.DataValidationWarningException;
import org.ebayopensource.turmeric.runtime.binding.impl.TypeConversionContextImpl;
import org.ebayopensource.turmeric.runtime.binding.schema.DataElementSchema;
import org.ebayopensource.turmeric.runtime.binding.utils.CollectionUtils;
import org.ebayopensource.turmeric.runtime.common.binding.DataBindingDesc;
import org.ebayopensource.turmeric.runtime.common.errors.ErrorDataProvider;
import org.ebayopensource.turmeric.runtime.common.exceptions.ErrorDataFactory;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceException;
import org.ebayopensource.turmeric.runtime.common.exceptions.ServiceRuntimeException;
import org.ebayopensource.turmeric.runtime.common.impl.binding.jaxb.TypeConversionAdapter;
import org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring.MetricsRegistrationHelper;
import org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring.SystemMetricDefs;
import org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring.SystemMetricDefs.OpLevelMetricDef;
import org.ebayopensource.turmeric.runtime.common.impl.internal.monitoring.SystemMetricDefs.SvcLevelMetricDef;
import org.ebayopensource.turmeric.runtime.common.impl.internal.service.BaseServiceDescFactory;
import org.ebayopensource.turmeric.runtime.common.impl.internal.service.ProtocolProcessorDesc;
import org.ebayopensource.turmeric.runtime.common.impl.internal.service.ServiceDesc;
import org.ebayopensource.turmeric.runtime.common.impl.internal.service.ServiceOperationDescImpl;
import org.ebayopensource.turmeric.runtime.common.impl.internal.utils.AsyncCallBack;
import org.ebayopensource.turmeric.runtime.common.impl.internal.utils.IAsyncResponsePoller;
import org.ebayopensource.turmeric.runtime.common.impl.pipeline.LoggingHandlerUtils;
import org.ebayopensource.turmeric.runtime.common.impl.utils.ErrorDataLoggingRegistry;
import org.ebayopensource.turmeric.runtime.common.impl.utils.LogManager;
import org.ebayopensource.turmeric.runtime.common.monitoring.MetricDef;
import org.ebayopensource.turmeric.runtime.common.monitoring.MetricsCollector;
import org.ebayopensource.turmeric.runtime.common.monitoring.value.MetricValueAggregator;
import org.ebayopensource.turmeric.runtime.common.pipeline.LoggingHandler;
import org.ebayopensource.turmeric.runtime.common.pipeline.LoggingHandlerStage;
import org.ebayopensource.turmeric.runtime.common.pipeline.Message;
import org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext;
import org.ebayopensource.turmeric.runtime.common.pipeline.MessageProcessingStage;
import org.ebayopensource.turmeric.runtime.common.pipeline.OutboundMessage;
import org.ebayopensource.turmeric.runtime.common.pipeline.ProtocolProcessor;
import org.ebayopensource.turmeric.runtime.common.pipeline.Transport;
import org.ebayopensource.turmeric.runtime.common.security.SecurityContext;
import org.ebayopensource.turmeric.runtime.common.service.ServiceContext;
import org.ebayopensource.turmeric.runtime.common.service.ServiceOperationDesc;
import org.ebayopensource.turmeric.runtime.common.service.ServiceOperationParamDesc;
import org.ebayopensource.turmeric.runtime.common.service.ServiceTypeMappings;
import org.ebayopensource.turmeric.runtime.common.types.ByteBufferWrapper;
import org.ebayopensource.turmeric.runtime.common.types.SOAConstants;
import org.ebayopensource.turmeric.runtime.common.types.SOAHeaders;
import org.ebayopensource.turmeric.runtime.common.types.ServiceAddress;
import org.ebayopensource.turmeric.runtime.common.utils.Preconditions;
import org.ebayopensource.turmeric.runtime.errorlibrary.ErrorConstants;
import org.ebayopensource.turmeric.common.v1.types.CommonErrorData;
import org.ebayopensource.turmeric.common.v1.types.ErrorCategory;
import org.ebayopensource.turmeric.common.v1.types.ErrorSeverity;
import com.ctc.wstx.exc.WstxParsingException;
/**
* Base implementation class of the message context.
*
* @see org.ebayopensource.turmeric.runtime.common.pipeline.MessageContext
* @author ichernyshev
*/
public abstract class BaseMessageContextImpl<D extends ServiceDesc, C extends ServiceContext>
implements MessageContext {
private static final Logger LOGGER = LogManager.getInstance(BaseMessageContextImpl.class);
private final D m_serviceDesc;
private final C m_serviceCtx;
protected ProtocolProcessorDesc m_protocolProcessor;
private final Transport m_transport;
private final BaseMessageImpl m_requestMessage;
private final BaseMessageImpl m_responseMessage;
private final ServiceOperationDescImpl m_operation;
private final ServiceAddress m_clientAddress;
private final ServiceAddress m_serviceAddress;
protected Map<String, Object> m_systemProperties;
private MessageProcessingStage m_processingStage;
private Object m_authenticatedUser;
private List<CommonErrorData> m_responseResidentErrors;
private List<Throwable> m_errors;
private List<Throwable> m_warnings;
protected Map<String, Object> m_userProperties;
private String m_requestId;
private String m_requestGuid;
private final String m_serviceVersion;
private final Charset m_effectiveCharset;
protected SecurityContext m_securityContext;
private final String m_requestUri;
private final String m_serviceLayer;
private boolean m_inboundRawMode;
private boolean m_outboundRawMode;
private AsyncMessageContextImpl m_asynMessageContext;
private IAsyncResponsePoller m_servicePoller;
private List<Object> m_outParams;
private ByteBufferWrapper m_outWrapper;
protected Map<String, String> m_queryParams;
protected Map<String, String> m_rawQueryParams;
/**
* Internal constructor to be called by the derived classes.
*
* @param serviceDesc
* the service description (processed configuration and
* associated extension classes and state) for the service
* which is currently being invoked
* @param operation
* the processed configuration of the operation which is
* currently being invoked
* @param protocolProcessor
* the processed configuration and class name of the protocol
* processor which is currently operating on the invocation
* @param transport
* the processed configuration and class name of the
* transport being used to send and receive message data
* @param requestMessage
* the current request message
* @param responseMessage
* the current response
* @param clientAddress
* the ServiceAddress of the invoking client
* @param serviceAddress
* the ServiceAddress of the service endpoint instance
* @param systemProperties
* a map holding any object state required for the duration
* of the service processing; state data is held until
* processing completes, even in asynchronous processing
* @param serviceVersion
* the version of the service which is being invoked
* @param effectiveCharset
* the character set in which the client or service is
* configured to process information; deserialization occurs
* into this target character set
*/
protected BaseMessageContextImpl(D serviceDesc, ServiceOperationDesc operation, ProtocolProcessorDesc protocolProcessor,
Transport transport, BaseMessageImpl requestMessage, BaseMessageImpl responseMessage, ServiceAddress clientAddress,
ServiceAddress serviceAddress, Map<String, Object> systemProperties, String serviceVersion,
Charset effectiveCharset, String requestUri) throws ServiceException {
// Check the input parameters
Preconditions.checkNotNull(serviceDesc);
Preconditions.checkNotNull(operation);
Preconditions.checkNotNull(transport);
Preconditions.checkNotNull(serviceAddress);
m_serviceDesc = serviceDesc;
m_operation = (ServiceOperationDescImpl) operation;
m_protocolProcessor = protocolProcessor;
m_transport = transport;
m_requestMessage = requestMessage;
m_responseMessage = responseMessage;
m_clientAddress = clientAddress;
m_serviceAddress = serviceAddress;
m_systemProperties = systemProperties;
m_effectiveCharset = effectiveCharset;
m_requestUri = requestUri;
m_processingStage = MessageProcessingStage.REQUEST_INIT;
if (serviceDesc.getServiceId().isClientSide()) {
@SuppressWarnings("unchecked")
C serviceCtx = (C) BaseServiceDescFactory.getClientInstance().getServiceContext(serviceDesc);
m_serviceCtx = serviceCtx;
} else {
@SuppressWarnings("unchecked")
C serviceCtx = (C) BaseServiceDescFactory.getServerInstance().getServiceContext(serviceDesc);
m_serviceCtx = serviceCtx;
}
/*
* request message is not required for retrieve of Service Similarly,
* response message is not required from invokeAsync method of Service
*/
if (m_requestMessage != null)
m_requestMessage.setContext(this);
if (m_responseMessage != null)
m_responseMessage.setContext(this);
if (m_serviceDesc.isFallback()) {
m_serviceLayer = null;
m_serviceVersion = null;
} else {
m_serviceLayer = m_serviceDesc.getConfig().getMetaData().getLayer();
if (null != serviceVersion) {
m_serviceVersion = serviceVersion;
} else {
m_serviceVersion = m_serviceDesc.getConfig().getMetaData().getVersion();
}
}
}
/**
* Returns the service description (processed configuration and associated
* extension classes and state) for the currently operating service.
*
* @return the service description
*/
public final D getServiceDesc() {
return m_serviceDesc;
}
/**
* Returns the service context
*
* @return service context.
*/
public C getServiceContext() {
return m_serviceCtx;
}
/**
* Returns the admin name in the service description
*
* @return the adminName
*/
public final String getAdminName() {
return m_serviceDesc.getAdminName();
}
/**
* Returns the service QName
*
* @return the service name
*/
public final QName getServiceQName() {
return m_serviceDesc.getServiceQName();
}
/**
* Returns the operation
*
* @return a <code>ServiceOperationDescImpl</code> object representing the operation
*/
public final ServiceOperationDescImpl getOperation() {
return m_operation;
}
/**
* Returns the operation name
*
* @return a <code>String</code>, operation name
*/
public final String getOperationName() {
return m_operation.getName();
}
/**
* Returns the processed configuration and class name of the protocol
* processor which is currently operating on the invocation
*
* @return the protocol processor configuration
*/
public final ProtocolProcessor getProtocolProcessor() {
return m_protocolProcessor.getProcessor();
}
/**
* Sets the processed configuration and class name of the protocol processor
* which is currently operating on the invocation
*/
public final void setProtocolProcessor(ProtocolProcessorDesc processor) {
m_protocolProcessor = processor;
}
/**
* Returns the protocol processor name
* which is currently operating on the invocation
*
* @return a <code>String</code> representing the message protocol
*/
public final String getMessageProtocol() {
return getProtocolProcessor().getMessageProtocol();
}
/**
* Returns the processed configuration and class name of the transport being
* used to send and receive message data
*
* @return the transport configuration
*/
public final Transport getTransport() {
return m_transport;
}
/**
* Returns the client address
*
* @return the client address as a <code>ServiceAddress</code> object
*/
public final ServiceAddress getClientAddress() {
return m_clientAddress;
}
/**
* Returns the service address
*
* @return the service address as a <code>ServiceAddress</code> object
*/
public final ServiceAddress getServiceAddress() {
return m_serviceAddress;
}
/**
* Returns the current version of the service
*
* @return a <code>String</code> representing the service version
*/
public final String getServiceVersion() {
return m_serviceVersion;
}
/**
* Returns the Charset.
*
* @return a <code>Charset</code>
*/
public final Charset getEffectiveCharset() {
return m_effectiveCharset;
}
/**
* Returns the request URI.
*
* @return the URI <code>String</code>
*/
public final String getRequestUri() {
return m_requestUri;
}
/**
* The Property associated with the parameter name.
*
* @param name the name of the property
* @return an <code>Object</code>
* @throws <code>NullPointerException</code>, if the <code>name</code> is null
*/
public final Object getProperty(String name) {
Preconditions.checkNotNull(name, "Property name can not be null");
if (m_systemProperties != null && m_systemProperties.containsKey(name)) {
return m_systemProperties.get(name);
}
if (name.startsWith(SOAConstants.CTX_PROP_PREFIX)) {
return null;
}
if (m_userProperties != null) {
return m_userProperties.get(name);
}
return null;
}
/**
* Returns the service layer
*
* @return the service layer as a <code>String</code>
*/
public String getServiceLayer() {
return m_serviceLayer;
}
/**
* Sets the property <name,value> pair
*
* @param name the property name
* @param value the <code>Object</code> value for the property
* @throws <code>ServiceException</code> if the property passed is a System property
*/
public final void setProperty(String name, Object value) throws ServiceException {
if ((m_systemProperties != null && m_systemProperties.containsKey(name))
|| (name.startsWith(SOAConstants.CTX_PROP_PREFIX))) {
throw new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_RT_CANNOT_SET_SYSTEM_PROP,
ErrorConstants.ERRORDOMAIN, new Object[] { name }));
}
if (m_userProperties == null) {
m_userProperties = new HashMap<String, Object>();
}
m_userProperties.put(name, value);
}
/**
* Internal method to set a SOA framework-specific property. Service writers
* and consumers should never call this method.
*
* @param name the name of the property
* @param value state information associated with the property
*/
public final void setSystemProperty(String name, Object value) {
// DO NOT make this method public on MessageContext interface
if (m_systemProperties == null) {
m_systemProperties = new HashMap<String, Object>();
}
m_systemProperties.put(name, value);
}
/**
* Returns the request message
*
* @return a request <code>Message</code> object
*/
public final Message getRequestMessage() {
return m_requestMessage;
}
/**
* Returns the response message
*
* @return a response <code>Message</code> object
*/
public final Message getResponseMessage() {
return m_responseMessage;
}
/**
* Adds a RRE error. Logs the error to CAL and updates the metrics accordingly
*
* @param errorData the error data object to add.
*/
public final void addResponseResidentError(CommonErrorData errorData) {
Preconditions.checkNotNull(errorData);
for (LoggingHandler loggingHandler : m_serviceDesc.getLoggingHandlers()) {
try {
loggingHandler.logResponseResidentError(this, errorData);
} catch (Throwable loggingError) {
logLoggingError(loggingError, errorData);
}
}
addErrorMetricData(errorData);
if (m_responseResidentErrors == null) {
m_responseResidentErrors = new ArrayList<CommonErrorData>();
}
m_responseResidentErrors.add(errorData);
ErrorDataLoggingRegistry.getInstance().remove(errorData);
}
/**
* Adds the <code>Throwable</code>. Updates the metrics and the CAL info.
*
* @param t the Throwable to be added
*/
public final void addError(Throwable t) {
Preconditions.checkNotNull(t, new ServiceRuntimeException(
ErrorDataFactory.createErrorData(ErrorConstants.SVC_RT_NULL_ERROR_DATA, ErrorConstants.ERRORDOMAIN)));
t = validateNewError(t);
for (LoggingHandler loggingHandler : m_serviceDesc.getLoggingHandlers()) {
try {
if (t instanceof DataValidationErrorException || t instanceof WstxParsingException) {
loggingHandler.logWarning(this, t);
} else {
loggingHandler.logError(this, t);
}
} catch (Throwable loggingError) {
logLoggingError(loggingError, t);
}
}
addErrorMetricData(t);
if (m_errors == null) {
m_errors = new ArrayList<Throwable>();
}
m_errors.add(convertToServiceException(t));
}
/**
* Update the metric for the passed metric defintion
*
* @param def the metric definition
* @param count the number that has to be added to the metric
*/
public final void updateSvcMetric(SystemMetricDefs.SvcLevelMetricDef def, long count) {
m_serviceDesc.updateMetric(this, def, count);
}
/**
* Update the service and operation time metrics
*
* @param def the <code>OpLevelMetricDef</code> metric
* @param startTime starting time
* @param timeSpan the time span
*/
public final void updateSvcAndOpMetric(OpLevelMetricDef def, long startTime, long timeSpan) {
OpLevelMetricDef startTimeOpMetric = SystemMetricDefs.getStartTimeOperationMetrics(def);
if (null != startTimeOpMetric) {
Long processingStartTime = (Long) getProperty(SystemMetricDefs.CTX_KEY_MSG_PROCESSING_STARTED);
if (null != processingStartTime) {
long relativeStartTime = startTime - processingStartTime.longValue();
m_serviceDesc.updateMetric(this, startTimeOpMetric.getSvcDef(), relativeStartTime);
m_operation.updateMetric(this, startTimeOpMetric, relativeStartTime);
}
}
m_serviceDesc.updateMetric(this, def.getSvcDef(), timeSpan);
m_operation.updateMetric(this, def, timeSpan);
}
/**
* Update the service and operation count metrics
*
* @param def the <code>OpLevelMetricDef</code> metric
* @param count the count to increase
*/
public final void updateSvcAndOpMetric(OpLevelMetricDef def, long count) {
m_serviceDesc.updateMetric(this, def.getSvcDef(), count);
m_operation.updateMetric(this, def, count);
}
/**
* Update the service count metrics by 1
*
* @param def the <code>SvcLevelMetricDef</code> metric
*/
public final void incrementSvcMetric(SvcLevelMetricDef def) {
m_serviceDesc.updateMetric(this, def, 1);
}
/**
* Update the service and operation count metrics by 1
*
* @param def the <code>OpLevelMetricDef</code> metric
*/
public final void incrementSvcAndOpMetric(OpLevelMetricDef def) {
m_serviceDesc.updateMetric(this, def.getSvcDef(), 1);
m_operation.updateMetric(this, def, 1);
}
/**
* Adds the warning. Logs the warning using the configured LoggingHandlers.
*
* @param t <code>Throwable</code> that has to be added
*/
public final void addWarning(Throwable t) {
Preconditions.checkNotNull(t);
List<LoggingHandler> loggingHandlers = m_serviceDesc.getLoggingHandlers();
for (LoggingHandler loggingHandler : loggingHandlers) {
try {
loggingHandler.logWarning(this, t);
} catch (Throwable e2) {
logLoggingError(e2, t);
}
}
if (m_warnings == null) {
m_warnings = new ArrayList<Throwable>();
}
m_warnings.add(convertToServiceException(t));
}
/**
* Returns <code>true</code> if there are any RRE errors
*
* @return <code>true</code> if RRE exists, <code>false</code> otherwise
*/
public boolean hasResponseResidentErrors() {
return m_responseResidentErrors == null ? false : !m_responseResidentErrors.isEmpty();
}
/**
* Return <code>true</code> if there are any errors
*
* @return a boolean value to indicate whether there are errors or not
*/
public boolean hasErrors() {
return m_errors == null ? false : !m_errors.isEmpty();
}
/**
* Returns the list of warnings
*
* @return a List of <code>Throwable</code>s if there are warnings. A list of size 0 is returned, if there are no warnings
*/
public final List<Throwable> getWarningList() {
if (m_warnings != null) {
return Collections.unmodifiableList(m_warnings);
}
return CollectionUtils.EMPTY_THROWABLE_LIST;
}
/**
* Internal method to set the current list of warnings (exceptions in the
* pipeline that were recovered via the continue-on-error feature)
*
* @param list
* the list of warnings
*/
public final void setWarningList(List<Throwable> list) {
m_warnings = list;
}
/**
* Returns the list of RRE errors
*
* @return a unmodifiable list of RRE errors. A list of size 0 is returned, if there are no warnings
*/
public final List<CommonErrorData> getResponseResidentErrorList() {
if (m_responseResidentErrors != null) {
return Collections.unmodifiableList(this.m_responseResidentErrors);
}
return Collections.unmodifiableList(new ArrayList<CommonErrorData>());
}
/**
* Returns the list of Errors
*
* @return a unmodifiable list of errors. A list of size 0 is returned, if there are no warnings
*/
public final List<Throwable> getErrorList() {
if (m_errors != null) {
return Collections.unmodifiableList(m_errors);
}
return CollectionUtils.EMPTY_THROWABLE_LIST;
}
/**
* Returns the authenticated user
*
* @return an <code>Object</code> representing the user
*/
public final Object getAuthenticatedUser() {
return m_authenticatedUser;
}
/**
* Sets the passed in user as the authenticated user
*
* @param user a user object to set.
*/
public final void setAuthenticatedUser(Object user) {
m_authenticatedUser = user;
}
/**
* Internal method to change the current processing stage during pipeline
* operation. Service writers or consumers should never call this method.
*
* @param value
*/
public final void changeProcessingStage(MessageProcessingStage value) {
Preconditions.checkNotNull(value);
m_processingStage = value;
}
/**
* Logs the processing stage for each of the Logging handlers configured.
*
* @param stage the Logging handler stage.
*/
public final void runLoggingHandlerStage(LoggingHandlerStage stage) {
List<LoggingHandler> loggingHandlers = m_serviceDesc.getLoggingHandlers();
if (stage == LoggingHandlerStage.REQUEST_STARTED || stage == LoggingHandlerStage.BEFORE_REQUEST_DISPATCH
|| stage == LoggingHandlerStage.REQUEST_DISPATCH_START) {
for (int i = 0; i < loggingHandlers.size(); i++) {
LoggingHandler loggingHandler = loggingHandlers.get(i);
try {
loggingHandler.logProcessingStage(this, stage);
} catch (Throwable e) {
logLoggingError(e, "Processing stage " + stage + " for service "
+ getServiceQName() + ", operation " + getOperationName());
}
}
} else {
for (int i = loggingHandlers.size() - 1; i >= 0; i--) {
LoggingHandler loggingHandler = loggingHandlers.get(i);
try {
loggingHandler.logProcessingStage(this, stage);
} catch (Throwable e) {
logLoggingError(e, "Processing stage " + stage + " for service "
+ getServiceQName() + ", operation " + getOperationName());
}
}
}
}
/**
* Internal method to reset the state of the request message and allow
* freeing of associated memory. Service writers and consumers should never
* call this method.
*/
public final void cleanupRequestData() {
m_requestMessage.cleanupData();
}
/**
* Returns the current processing stage
*
* @return the processing stage
*/
public final MessageProcessingStage getProcessingStage() {
return m_processingStage;
}
/**
* Returns the request id
*
* @return the request id as a <code>String</code>
*/
public final String getRequestId() {
return m_requestId;
}
/**
* Returns the request GUID
*
* @return the request GUID as a <code>String</code>
*/
public String getRequestGuid() {
if (m_requestGuid == null && m_requestId != null) {
// lazy parsing
m_requestGuid = parseGuid(m_requestId);
}
return m_requestGuid;
}
/**
* Sets the passed string as the request GUID
*
* @param guid a <code>String</code> to set as the request guid
*/
public void setRequestGuid(String guid) {
m_requestGuid = guid;
}
/**
* Sets the request ID and GUID
*
* @param requestID the request ID
* @param requestGuid the request GUID
*/
public final void setRequestId(String requestId, String requestGuid) throws ServiceException {
// Preconditions.checkArgument(requestId != null && requestGuid != null, "Both request Id and request GUID cant be null at the same time")
// TODO IS the logic correct?
if (requestId == null && requestGuid == null) {
throw new NullPointerException();
}
if (requestId == null) {
// setting both ID and GUID to be the same as GUID
m_requestId = requestGuid;
m_requestGuid = requestGuid;
return;
}
m_requestId = requestId;
m_requestGuid = requestGuid;
}
/**
* Returns the security context.
* @return the <code>SecurityContext</code> object
*/
public SecurityContext getSecurityContext() {
return m_securityContext;
}
/**
* Internal method to construct outbound meta-information such as HTTP
* headers, for handover to the transport.
*
* @param customHeaders
* the map of header information from which to construct the
* outbound transport header map
* @return the resulting transport header map
* @throws ServiceException
*/
protected abstract Map<String, String> buildOutputHeaders(Map<String, String> customHeaders) throws ServiceException;
/**
* Sub classes may override this method to process the inbound headers.
*
* @param transportHeaders
* @throws ServiceException
*/
protected void processInboundHeaders(Map<String, String> transportHeaders) throws ServiceException {
// allow override
}
/**
* Validation hook for the subclasses to extend.
*
* This implementation returns the Throwable that is passed.
*
* @param t the throwable that has to be validated.
* @return the Throwable that has been validated.
*/
protected Throwable validateNewError(Throwable t) {
return t;
}
/**
* Returns <code>true</code> if the inbound raw mode is set, <code>false</code> otherwise
*
* @return the inbound raw mode
*/
public boolean isInboundRawMode() {
return m_inboundRawMode;
}
/**
* Sets the inbound raw mode
*
* @param mode a boolean value for the mode
*/
public void setInboundRawMode(boolean mode) {
m_inboundRawMode = mode;
}
/**
* Returns <code>true</code> if the outbound raw mode is set, <code>false</code> otherwise
*
* @return the inbound raw mode
*/
public boolean isOutboundRawMode() {
return m_outboundRawMode;
}
/**
* Sets the outbound raw mode
*
* @param mode a boolean value for the mode
*/
public void setOutboundRawMode(boolean mode) {
m_outboundRawMode = mode;
}
/**
* Sets the client async handler
*
* @param handler a <code>AsyncHandler</code> to set
*/
public void setClientAsyncHandler(AsyncHandler handler) {
prepareAsyncMessageContext();
m_asynMessageContext.setClientAsyncHandler(handler);
}
/**
* Returns the Client asyc handler.
*
* @return the async handler if present, else <code>null</code>
*/
public AsyncHandler getClientAsyncHandler() {
return m_asynMessageContext == null ? null : m_asynMessageContext.getClientAsyncHandler();
}
/**
* Returns the Future Object in the asyncmessageContext
*
* @return the Future object
*/
public Future<?> getFutureResponse() {
return m_asynMessageContext == null ? null : m_asynMessageContext.getFutureResponse();
}
/**
* Sets the passed future object to the message context
*
* @param futureResponse the future response to set
*/
public void setFutureResponse(Future<?> futureResponse) {
prepareAsyncMessageContext();
m_asynMessageContext.setFutureResponse(futureResponse);
}
/**
* Returns the Executor associated with the Message context
*
* @return returns the <code>Executor</code>
*/
public Executor getExecutor() {
return m_asynMessageContext == null ? null : m_asynMessageContext.getExecutor();
}
/**
* Sets the Executor in the Message Context
*
* @param executor an <code>Executor</code>to set
*/
public void setExecutor(Executor executor) {
prepareAsyncMessageContext();
m_asynMessageContext.setExecutor(executor);
}
/**
* Sets the Service asynchronous Call back in the Message Context
*
* @param callback the <code>AsyncCallBack</code> variable to set
*/
public void setServiceAsyncCallback(AsyncCallBack callback) {
prepareAsyncMessageContext();
m_asynMessageContext.setServiceAsyncCallback(callback);
}
/**
* Returns the <code>AsyncCallBack</code> associated with the Message Context.
*
* @return the AsynCallBack object
*/
public AsyncCallBack getServiceAsyncCallback() {
return m_asynMessageContext == null ? null : m_asynMessageContext.getServiceAsyncCallback();
}
public String getPayloadType() {
String payloadType = null;
try {
payloadType = getCurrentMessage().getPayloadType();
} catch (ServiceException se) {
// DataBindingDesc.getPayloadType() doesn't throw exceptions
}
return payloadType;
}
public String getDefaultNamespace() {
return getServiceQName().getNamespaceURI();
}
public String getSingleNamespace() {
return getServiceContext().getTypeMappings().getSingleNamespace();
}
public Map<String, List<String>> getNamespaceToPrefixMap() {
ServiceTypeMappings typeMappings = getServiceContext().getTypeMappings();
Map<String, List<String>> ns2Prefix = typeMappings.getNamespaceToPrefixesMap();
return ns2Prefix;
}
public Map<String, String> getPrefixToNamespaceMap() {
ServiceTypeMappings typeMappings = getServiceContext().getTypeMappings();
Map<String, String> prefix2NS = typeMappings.getPrefixToNamespaceMap();
return prefix2NS;
}
/**
* Returns the char set
* @return the char set
*/
public Charset getCharset() {
Charset c = null;
try {
c = getCurrentMessage().getG11nOptions().getCharset();
} catch (ServiceException se) {
// Shouldn't throw an exception
}
return c;
}
public String getNsForJavaType(Class javaType) {
return getServiceContext().getTypeMappings().getNsForJavaType(javaType);
}
public Class getRootClass() {
List<Class> paramTypes = null;
try {
paramTypes = getCurrentMessage().getParamDesc().getRootJavaTypes();
} catch (ServiceException se) {
// Shouldn't throw an exception
}
Class topElementClass = paramTypes == null || paramTypes.size() == 0 ? null : paramTypes.get(0);
return topElementClass;
}
public ITypeConversionContext getTypeConversionContext() {
DataBindingDesc dbDesc = null;
try {
dbDesc = getCurrentMessage().getDataBindingDesc();
} catch (ServiceException se) {
// Simple getter, doesn't really throw anything
}
ITypeConversionContext tcCtxt = null;
if (dbDesc != null) {
tcCtxt = new TypeConversionContextImpl(dbDesc.getAllTypeConverterBoundTypes(), dbDesc
.getAllTypeConverterValueTypes(), TypeConversionAdapter.class);
}
return tcCtxt;
}
private ServiceOperationParamDesc getParamDesc() {
ServiceOperationParamDesc paramDesc = null;
try {
paramDesc = getCurrentMessage().getParamDesc();
} catch (ServiceException se) {
// getParamDesc() doesn't throw any exceptions
}
return paramDesc;
}
public QName getRootXMLName() {
QName rootXmlName = getRootClass() == null ? null : getParamDesc().getXmlNameForJavaType(getRootClass());
return rootXmlName;
}
public DataElementSchema getRootElementSchema() {
DataElementSchema rootSchema = getRootClass() == null ? null : getParamDesc().getRootElements().get(0);
return rootSchema;
}
public boolean isREST() {
Message m = getCurrentMessage();
if (m instanceof OutboundMessage) {
return ((OutboundMessage) m).isREST();
}
return false;
}
public boolean isElementOrderPreserved() {
Message msg = getCurrentMessage();
if (null == msg) {
return true;
}
try {
String headerString = msg.getTransportHeader(SOAHeaders.ELEMENT_ORDERING_PRESERVE);
if (null == headerString) {
return true;
}
return Boolean.parseBoolean(headerString);
} catch (ServiceException se) {
return true;
}
}
public Message getCurrentMessage() {
return getProcessingStage().isRequestDirection() ? getRequestMessage() : getResponseMessage();
}
private static Throwable convertToServiceException(Throwable t) {
if (t instanceof DataValidationWarningException) {
DataValidationWarningException warning = (DataValidationWarningException) t;
return new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_DATA_VALIDATION_WARNING, ErrorConstants.ERRORDOMAIN,
new Object[] {new Integer(warning.getRow()), new Integer(warning.getCol()), warning.getMessage() }), t.getCause());
} else if (t instanceof DataValidationErrorException) {
DataValidationErrorException error = (DataValidationErrorException) t;
return new ServiceException(ErrorDataFactory.createErrorData(ErrorConstants.SVC_DATA_VALIDATION_ERROR, ErrorConstants.ERRORDOMAIN,
new Object[] { new Integer(error.getRow()), new Integer(error.getCol()), error.getMessage() }), t.getCause());
}
return t;
}
public IAsyncResponsePoller getServicePoller() {
return m_servicePoller;
}
public void setServicePoller(IAsyncResponsePoller poller) {
m_servicePoller = poller;
}
public void setOutParams(List<Object> outParams) {
m_outParams = outParams;
}
public List<Object> getOutParams() {
return m_outParams;
}
/**
*
* @param outWrapper
*/
public void setOutBuffer(ByteBufferWrapper outWrapper) {
m_outWrapper = outWrapper;
}
/**
*
* @return
*/
public ByteBufferWrapper getOutBuffer() {
return m_outWrapper;
}
/**
* Returns the
*/
public boolean isAsync() {
return m_asynMessageContext != null;
}
protected void prepareAsyncMessageContext() {
if (m_asynMessageContext == null) {
m_asynMessageContext = new AsyncMessageContextImpl();
}
}
public ErrorDataProvider getErrorDataProvider() {
return m_serviceDesc.getErrorDataProviderClass();
}
public Map<String,String> getQueryParams() {
return m_queryParams;
}
public Map<String,String> getRawQueryParams() {
return m_rawQueryParams;
}
private String parseGuid(String id) {
int delimiterIdx = id.indexOf('!');
if (delimiterIdx >= 0) {
return id.substring(0, delimiterIdx);
}
return id;
}
private void updateTotalErrorMetric() {
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_TOTAL);
}
private void updateErrorSeverityMetrics(final ErrorSeverity severity) {
if (severity == ErrorSeverity.ERROR) {
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_SEVERITY_ERROR);
} else if (severity == ErrorSeverity.WARNING) {
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_SEVERITY_WARNING);
}
}
private void updateErrorCategoryMetrics(final CommonErrorData errorData) {
try {
ErrorCategory category = errorData.getCategory();
if (category == ErrorCategory.APPLICATION) {
// For Application category, return without updating the sub domain metric.
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_CAT_APPLICATION);
return;
} else if (category == ErrorCategory.SYSTEM) {
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_CAT_SYSTEM);
} else if (category == ErrorCategory.REQUEST) {
incrementSvcAndOpMetric(SystemMetricDefs.OP_ERR_CAT_REQUEST);
}
updateErrorSubdomainMetrics(errorData);
} catch (Exception e) {
logMetricUpdateError(e, errorData);
}
}
private void addErrorMetricData(final CommonErrorData errorData) {
Preconditions.checkNotNull(errorData);
updateErrorCategoryMetrics(errorData);
updateErrorSeverityMetrics(errorData.getSeverity());
updateErrorGroupMetric(errorData);
updateTotalErrorMetric();
}
private void updateErrorSubdomainMetrics(final CommonErrorData errorData) {
MetricDef metric =
MetricsRegistrationHelper.createSubDomainMetrics(errorData, getServiceId().isClientSide());
if(metric != null) {
boolean clientSide = m_serviceDesc.getServiceId().isClientSide();
MetricValueAggregator valueAgg = null;
if (clientSide) {
valueAgg = MetricsCollector.getClientInstance().getMetricValue(((OpLevelMetricDef)metric).getSvcDef().getMetricName(),
m_serviceDesc.getServiceId(), null);
} else {
valueAgg = MetricsCollector.getServerInstance().getMetricValue(((OpLevelMetricDef)metric).getSvcDef().getMetricName(),
m_serviceDesc.getServiceId(), null);
}
if (valueAgg != null)
valueAgg.update(1);
}
}
private void updateErrorGroupMetric(CommonErrorData... errDatas) {
List<SystemMetricDefs.OpLevelErrorMetricDef> groupMetricDefs = null;
if (errDatas != null) {
for (CommonErrorData errorData : errDatas) {
try {
if (errorData != null) {
groupMetricDefs = MetricsRegistrationHelper.getGroupMetricDefs(errorData);
if (groupMetricDefs != null) {
for (SystemMetricDefs.OpLevelErrorMetricDef def : groupMetricDefs) {
updateErrorGroupMetric(def);
}
}
// Remove the reference in the
// MetricsRegistrationHelper, as we
// are done updating the metrics
MetricsRegistrationHelper.remove(errorData);
}
} catch (Exception e) {
logMetricUpdateError(e, errorData);
}
}
}
}
private void updateErrorGroupMetric(SystemMetricDefs.OpLevelErrorMetricDef def) {
boolean clientSide = m_serviceDesc.getServiceId().isClientSide();
MetricValueAggregator valueAgg = null;
if (clientSide) {
valueAgg = MetricsCollector.getClientInstance().getMetricValue(def.getSvcDef().getMetricName(),
m_serviceDesc.getServiceId(), null);
} else {
valueAgg = MetricsCollector.getServerInstance().getMetricValue(def.getSvcDef().getMetricName(),
m_serviceDesc.getServiceId(), null);
}
if (valueAgg != null)
valueAgg.update(1);
if (clientSide) {
valueAgg = MetricsCollector.getClientInstance().getMetricValue(def.getMetricName(), m_serviceDesc.getServiceId(),
this.getOperationName());
} else {
valueAgg = MetricsCollector.getServerInstance().getMetricValue(def.getMetricName(), m_serviceDesc.getServiceId(),
this.getOperationName());
}
if (valueAgg != null)
valueAgg.update(1);
}
private void addErrorMetricData(final Throwable t) {
LoggingHandlerUtils utils = getLoggingHandlerUtils();
// t has one or more errorData associated.
List<CommonErrorData> errorDatas = utils.getErrorData(t);
if (errorDatas != null) {
for (final CommonErrorData errorData : errorDatas) {
addErrorMetricData(errorData);
ErrorDataLoggingRegistry.getInstance().remove(errorData);
}
}
}
protected abstract LoggingHandlerUtils getLoggingHandlerUtils();
private void logMetricUpdateError(Throwable t, CommonErrorData errorData) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"Error in Update of Error Category/Group Metrics '" + errorData + "'. " + t.toString());
}
}
private void logLoggingError(Throwable e, CommonErrorData errorData) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"Unable to log response resident error '" + errorData + "' due to error in logger: " + e.toString());
}
}
private void logLoggingError(Throwable e, Throwable originalEx) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"Unable to log exception '" + originalEx + "' due to error in logger: " + e.toString());
}
}
private void logLoggingError(Throwable e, String message) {
if (LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING,
"Unable to log message '" + message + "' due to error in logger: " + e.toString(),
e);
}
}
}