/*
* #%L
* Service Activity Monitoring :: Agent
* %%
* Copyright (C) 2011 - 2012 Talend 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.
* #L%
*/
package org.talend.esb.sam.agent.flowidprocessor;
import java.lang.ref.WeakReference;
import java.util.ListIterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.interceptor.Interceptor;
import org.apache.cxf.message.Exchange;
import org.apache.cxf.message.Message;
import org.apache.cxf.message.MessageUtils;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.phase.PhaseInterceptorChain;
import org.apache.cxf.ws.addressing.ContextUtils;
import org.talend.esb.sam.agent.eventproducer.EventProducerInterceptor;
import org.talend.esb.sam.agent.message.FlowIdHelper;
/**
* The Class FlowIdProducerOut used for writing FlowId in outcoming messages.
*
* @param <T>
* the generic type
*/
public class FlowIdProducerOut<T extends Message> extends
AbstractPhaseInterceptor<T> {
private static final Logger LOG = Logger.getLogger(FlowIdProducerOut.class
.getName());
/**
* Instantiates a new flow id producer out.
*/
public FlowIdProducerOut() {
super(Phase.USER_LOGICAL);
}
/*
* (non-Javadoc)
*
* @see
* org.apache.cxf.interceptor.Interceptor#handleMessage(org.apache.cxf.message
* .Message)
*/
public void handleMessage(T message) throws Fault {
if (LOG.isLoggable(Level.FINEST)) {
LOG.finest("FlowIdProducerOut Interceptor called. isOutbound: "
+ MessageUtils.isOutbound(message) + ", isRequestor: "
+ MessageUtils.isRequestor(message));
}
if (MessageUtils.isRequestor(message)) {
handleRequestOut(message);
} else {
handleResponseOut(message);
}
// Don't write flowId for Oneway responses
if (isOnewayResponse(message)) {
return;
}
// write FlowId to HTTP and Soap layer
String flowId = FlowIdHelper.getFlowId(message);
FlowIdProtocolHeaderCodec.writeFlowId(message, flowId);
FlowIdSoapCodec.writeFlowId(message, flowId);
}
/**
* Handling out responce.
*
* @param message
* the message
* @throws Fault
* the fault
*/
protected void handleResponseOut(T message) throws Fault {
Message reqMsg = message.getExchange().getInMessage();
if (reqMsg == null) {
LOG.warning("InMessage is null!");
return;
}
// No flowId for oneway message
Exchange ex = reqMsg.getExchange();
if (ex.isOneWay()) {
return;
}
String reqFid = FlowIdHelper.getFlowId(reqMsg);
// if some interceptor throws fault before FlowIdProducerIn fired
if (reqFid == null) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Some interceptor throws fault.Setting FlowId in response.");
}
reqFid = FlowIdProtocolHeaderCodec.readFlowId(message);
}
// write IN message to SAM repo in case fault
if (reqFid == null) {
Message inMsg = ex.getInMessage();
reqFid = FlowIdProtocolHeaderCodec.readFlowId(inMsg);
if (null != reqFid) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("FlowId '" + reqFid
+ "' found in message of fault incoming exchange.");
LOG.fine("Calling EventProducerInterceptor to log IN message");
}
handleINEvent(ex, reqFid);
}
}
if (reqFid == null) {
reqFid = FlowIdSoapCodec.readFlowId(message);
}
if (reqFid != null) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("FlowId '" + reqFid + "' found in incoming message.");
}
} else {
reqFid = ContextUtils.generateUUID();
// write IN message to SAM repo in case fault
if (null != ex.getOutFaultMessage()) {
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("FlowId '" + reqFid
+ "' generated for fault message.");
LOG.fine("Calling EventProducerInterceptor to log IN message");
}
handleINEvent(ex, reqFid);
}
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("No flowId found in incoming message! Generate new flowId "
+ reqFid);
}
}
FlowIdHelper.setFlowId(message, reqFid);
}
/**
* Handling out request.
*
* @param message
* the message
* @throws Fault
* the fault
*/
protected void handleRequestOut(T message) throws Fault {
String flowId = FlowIdHelper.getFlowId(message);
if (flowId == null
&& message.containsKey(PhaseInterceptorChain.PREVIOUS_MESSAGE)) {
// Web Service consumer is acting as an intermediary
@SuppressWarnings("unchecked")
WeakReference<Message> wrPreviousMessage = (WeakReference<Message>) message
.get(PhaseInterceptorChain.PREVIOUS_MESSAGE);
Message previousMessage = (Message) wrPreviousMessage.get();
flowId = FlowIdHelper.getFlowId(previousMessage);
if (flowId != null && LOG.isLoggable(Level.FINE)) {
LOG.fine("flowId '" + flowId + "' found in previous message");
}
}
if (flowId == null) {
// No flowId found. Generate one.
flowId = ContextUtils.generateUUID();
if (LOG.isLoggable(Level.FINE)) {
LOG.fine("Generate new flowId '" + flowId + "'");
}
}
FlowIdHelper.setFlowId(message, flowId);
}
/**
* Calling EventProducerInterceptor in case of logging faults.
*
* @param exchange
* the message exchange
* @param reqFid
* the FlowId
*
* @throws Fault
* the fault
*/
protected void handleINEvent(Exchange exchange, String reqFid) throws Fault {
Message inMsg = exchange.getInMessage();
EventProducerInterceptor epi = null;
FlowIdHelper.setFlowId(inMsg, reqFid);
ListIterator<Interceptor<? extends Message>> interceptors = inMsg
.getInterceptorChain().getIterator();
while (interceptors.hasNext() && epi == null) {
Interceptor<? extends Message> interceptor = interceptors.next();
if (interceptor instanceof EventProducerInterceptor) {
epi = (EventProducerInterceptor) interceptor;
epi.handleMessage(inMsg);
}
}
}
protected boolean isOnewayResponse(T message) {
boolean isRequestor = MessageUtils.isRequestor(message);
boolean isFault = MessageUtils.isFault(message);
boolean isOutbound = MessageUtils.isOutbound(message);
return (message.getExchange().isOneWay()
&& ((isOutbound && !isRequestor) || (!isOutbound && isRequestor))
&& !isFault);
}
}