![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.servicemix.eip.patterns.AsyncBridge Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of servicemix-eip Show documentation
Show all versions of servicemix-eip Show documentation
The ServiceMix EIP component is a routing container where different routing patterns can be deployed as service unit.
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.servicemix.eip.patterns;
import java.util.Date;
import java.util.concurrent.TimeoutException;
import javax.jbi.messaging.ExchangeStatus;
import javax.jbi.messaging.InOnly;
import javax.jbi.messaging.InOut;
import javax.jbi.messaging.MessageExchange;
import javax.jbi.messaging.MessagingException;
import javax.jbi.messaging.NormalizedMessage;
import javax.jbi.messaging.RobustInOnly;
import org.apache.servicemix.common.util.MessageUtil;
import org.apache.servicemix.eip.EIPEndpoint;
import org.apache.servicemix.eip.support.ExchangeTarget;
import org.apache.servicemix.expression.Expression;
import org.apache.servicemix.expression.PropertyExpression;
import org.apache.servicemix.timers.Timer;
import org.apache.servicemix.timers.TimerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The async bridge pattern is used to bridge an In-Out exchange with two In-Only
* (or Robust-In-Only) exchanges. This pattern is the opposite of the {@link Pipeline}.
* The AsyncBridge uses a correlation identifier to be able to correlate the received
* In-Out exchange, the In-Only sent as the request and the In-Only received as the response.
* Defaults values are provided to configure those correlation ids. The default behavior
* is to use the exchange id of the incoming In-Out exchange as the correlation id and set
* it on the request exchange. The same property with the same value should be present on the
* response exchange in order for the AsyncBridge to work. ServiceMix components usually take
* care of propagating such properties, but failing to propagate it will result in errors.
*
* @author gnodet
* @see Pipeline
*
* @org.apache.xbean.XBean element="async-bridge"
*/
public class AsyncBridge extends EIPEndpoint {
public static final String CORRID = "org.apache.servicemix.eip.asyncbridge.corrid";
private final Logger logger = LoggerFactory.getLogger(AsyncBridge.class);
private Expression requestCorrId = new Expression() {
public Object evaluate(MessageExchange exchange, NormalizedMessage message) throws MessagingException {
return exchange.getExchangeId();
}
};
private String responseCorrIdProperty = CORRID;
private Expression responseCorrId;
private long timeout;
private ExchangeTarget target;
private boolean useRobustInOnly;
/**
* @return the timeout
*/
public long getTimeout() {
return timeout;
}
/**
* The timeout property controls the amount of time that the async bridge will wait for the response
* after having sent the request. The default value is 0 which means that no timeout apply. If set
* to a non zero value, a timer will be started when after the request is sent. When the timer
* expires, the In-Out exchange will be sent back with an error status and a
* {@link java.util.concurrent.TimeoutException} as the cause of the error.
* The value represents the number of milliseconds to wait.
*
* @param timeout the timeout to set
*/
public void setTimeout(long timeout) {
this.timeout = timeout;
}
/**
* @return the target
*/
public ExchangeTarget getTarget() {
return target;
}
/**
* The target which will be used to send an In-Only or Robust-In-Only exchange to.
* When receiving an In-Out exchange, the async bridge will create an In-Only request
* and send it to the specified target. It then expects another In-Only exchange to
* come back as the response, which will be set as the Out message on the In-Out exchange.
* This property is mandatory and must be set to a valid target.
*
* @param target the target to set
*/
public void setTarget(ExchangeTarget target) {
this.target = target;
}
/**
* @return the requestCorrId
*/
public Expression getRequestCorrId() {
return requestCorrId;
}
/**
* The expression used to compute the correlation id used to correlate the response and
* the request. The default behavior is to use the exchange id of the incoming In-Out
* exchange as the correlation id.
*
* @param requestCorrId the requestCorrId to set
* @see #setResponseCorrId(org.apache.servicemix.expression.Expression)
* @see #setResponseCorrIdProperty(String)
*/
public void setRequestCorrId(Expression requestCorrId) {
this.requestCorrId = requestCorrId;
}
/**
* @return the responseCorrIdProperty
*/
public String getResponseCorrIdProperty() {
return responseCorrIdProperty;
}
/**
* Name of the property used by default to compute the correlation id on the response
* exchange.
*
* @param responseCorrIdProperty the responseCorrIdProperty to set
* @see #setRequestCorrId(org.apache.servicemix.expression.Expression)
* @see #setResponseCorrId(org.apache.servicemix.expression.Expression)
*/
public void setResponseCorrIdProperty(String responseCorrIdProperty) {
this.responseCorrIdProperty = responseCorrIdProperty;
}
/**
* @return the responseCorrId
*/
public Expression getResponseCorrId() {
return responseCorrId;
}
/**
* The expression used to compute the correlation id from the response exchange.
* The value computed by this expression must match the one from the {@link #setRequestCorrId}
* expression. The default value is null, but if no specific expression is configured,
* an expression will be created which will extract the response correlation id from the
* {@link #setResponseCorrIdProperty(String)} property on the exchange.
*
* @param responseCorrId the responseCorrId to set
* @see #setResponseCorrIdProperty(String)
* @see #setRequestCorrId(org.apache.servicemix.expression.Expression)
*/
public void setResponseCorrId(Expression responseCorrId) {
this.responseCorrId = responseCorrId;
}
/**
* @return the useRobustInOnly
*/
public boolean isUseRobustInOnly() {
return useRobustInOnly;
}
/**
* Boolean flag to control if In-Only or Robust-In-Only exchange should be used
* when sending the request. The default value is false
which means
* that an In-Only exchange will be used. When using a Robust-In-Only exchange and
* when a fault is received, this fault will be sent back to the consumer on the In-Out
* exchange and the response exchange (if any) would be discarded.
* For both In-Only and Robust-In-Only, if the request exchange comes back with an Error
* status, this error will be conveyed back to the consumer in the same way.
*
* @param useRobustInOnly the useRobustInOnly to set
*/
public void setUseRobustInOnly(boolean useRobustInOnly) {
this.useRobustInOnly = useRobustInOnly;
}
/*
* (non-Javadoc)
* @see org.apache.servicemix.eip.EIPEndpoint#start()
*/
public void start() throws Exception {
super.start();
if (responseCorrId == null) {
responseCorrId = new PropertyExpression(responseCorrIdProperty);
}
}
/* (non-Javadoc)
* @see org.apache.servicemix.eip.EIPEndpoint#processSync(javax.jbi.messaging.MessageExchange)
*/
protected void processSync(MessageExchange exchange) throws Exception {
throw new IllegalStateException();
}
/* (non-Javadoc)
* @see org.apache.servicemix.eip.EIPEndpoint#processAsync(javax.jbi.messaging.MessageExchange)
*/
protected void processAsync(MessageExchange exchange) throws Exception {
throw new IllegalStateException();
}
/* (non-Javadoc)
* @see org.apache.servicemix.common.ExchangeProcessor#process(javax.jbi.messaging.MessageExchange)
*/
public void process(MessageExchange exchange) throws Exception {
// Three exchanges are involved: the first InOut will be called t0,
// the InOnly send will be called t1 and the InOnly received will be called t2
if (exchange.getRole() == MessageExchange.Role.PROVIDER) {
// Step1: receive t0 as the first message
if (exchange instanceof InOut && exchange.getStatus() == ExchangeStatus.ACTIVE) {
MessageExchange t0 = exchange;
MessageExchange t1;
final String correlationId = (String) requestCorrId.evaluate(t0, t0.getMessage("in"));
if (correlationId == null || correlationId.length() == 0) {
throw new IllegalArgumentException("Could not retrieve correlation id for incoming exchange");
}
store.store(correlationId + ".t0", t0);
t1 = useRobustInOnly ? getExchangeFactory().createRobustInOnlyExchange()
: getExchangeFactory().createInOnlyExchange();
target.configureTarget(t1, getContext());
MessageUtil.transferInToIn(t0, t1);
t1.setProperty(responseCorrIdProperty, correlationId);
t1.getMessage("in").setProperty(responseCorrIdProperty, correlationId);
send(t1);
// Receive the done / error from t0
} else if (exchange instanceof InOut && exchange.getStatus() != ExchangeStatus.ACTIVE) {
MessageExchange t0 = exchange;
MessageExchange t1;
MessageExchange t2;
final String correlationId = (String) requestCorrId.evaluate(t0, t0.getMessage("in"));
t1 = (MessageExchange) store.load(correlationId + ".t1");
t2 = (MessageExchange) store.load(correlationId + ".t2");
if (t1 != null) {
done(t1);
}
if (t2 != null) {
done(t2);
}
// Receive the response from t2
} else if ((exchange instanceof InOnly || exchange instanceof RobustInOnly) && exchange.getStatus() == ExchangeStatus.ACTIVE) {
MessageExchange t0;
MessageExchange t2 = exchange;
final String correlationId = (String) responseCorrId.evaluate(t2, t2.getMessage("in"));
if (correlationId == null || correlationId.length() == 0) {
throw new IllegalArgumentException("Could not retrieve correlation id for incoming exchange");
}
t0 = (MessageExchange) store.load(correlationId + ".t0");
// The request is found and has not timed out
if (t0 != null) {
store.store(correlationId + ".t2", t2);
MessageUtil.transferInToOut(t2, t0);
send(t0);
} else {
done(t2);
}
} else {
throw new IllegalStateException();
}
// Handle an exchange as a CONSUMER
} else {
// Step 2: receive t1 response
// If this is an error or a fault, transfer it from t1 to t0 and send,
// else, start a timeout to wait for t2
MessageExchange t1 = exchange;
// an error
final String correlationId = (String) t1.getProperty(responseCorrIdProperty);
if (t1.getStatus() == ExchangeStatus.ERROR) {
MessageExchange t0 = (MessageExchange) store.load(correlationId + ".t0");
// t1 response may come after t0, so in case this happens, we need to discard t1
if (t0 != null) {
fail(t0, t1.getError());
}
// a fault ?
} else if (exchange.getStatus() == ExchangeStatus.ACTIVE) {
MessageExchange t0 = (MessageExchange) store.load(correlationId + ".t0");
// t1 response may come after t0, so in case this happens, we need to discard t1
if (t0 != null) {
store.store(correlationId + ".t1", t1);
MessageUtil.transferFaultToFault(t1, t0);
send(t0);
}
// request sent successfully, start the timeout
} else {
Date exchangeTimeout = getTimeout(t1);
if (exchangeTimeout != null) {
getTimerManager().schedule(new TimerListener() {
public void timerExpired(Timer timer) {
AsyncBridge.this.onTimeout(correlationId);
}
}, exchangeTimeout);
}
}
}
}
protected void onTimeout(String correlationId) {
try {
MessageExchange t0 = (MessageExchange) store.load(correlationId + ".t0");
if (t0 != null) {
fail(t0, new TimeoutException());
}
} catch (Exception e) {
logger.debug("Exception caught when handling timeout", e);
}
}
protected Date getTimeout(MessageExchange exchange) {
if (timeout > 0) {
return new Date(System.currentTimeMillis() + timeout);
}
return null;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy