/*
* Copyright 2011 the original author or authors.
*
* 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.
*/
package io.vertx.ext.amqp.impl;
import io.vertx.codegen.annotations.Fluent;
import io.vertx.core.AsyncResult;
import io.vertx.core.Handler;
import io.vertx.core.Verticle;
import io.vertx.core.Vertx;
import io.vertx.core.eventbus.EventBus;
import io.vertx.core.eventbus.Message;
import io.vertx.core.eventbus.MessageConsumer;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.amqp.*;
import io.vertx.ext.amqp.impl.protocol.InboundMessage;
import io.vertx.ext.amqp.impl.protocol.LinkEventListener;
import io.vertx.ext.amqp.impl.protocol.LinkManager;
import io.vertx.ext.amqp.impl.protocol.MessageDisposition;
import io.vertx.ext.amqp.impl.routing.LinkRouter;
import io.vertx.ext.amqp.impl.routing.MessageRouter;
import io.vertx.ext.amqp.impl.translators.MessageTranslator;
import io.vertx.ext.amqp.impl.util.Functions;
import io.vertx.ext.amqp.impl.util.LogManager;
import io.vertx.ext.amqp.impl.util.LogMsgHelper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import static io.vertx.ext.amqp.impl.util.Functions.format;
import static io.vertx.ext.amqp.impl.util.Functions.print;
/**
* The service impl makes use of the LinkManager for AMQP connection/link
* management and the Router for routing logic.
*
* @author rajith
*/
public class AMQPServiceImpl implements Handler<Message<JsonObject>>, LinkEventListener, AMQPService {
private static final LogManager LOG = LogManager.get("AMQP-VERTX-BRIDGE:", AMQPServiceImpl.class);
private final Vertx _vertx;
private final EventBus _eb;
private final Map<String, Message<JsonObject>> _vertxReplyTo = new ConcurrentHashMap<String, Message<JsonObject>>();
private final AmqpServiceConfig _config;
private final String _replyToAddressPrefix;
private final List<MessageConsumer<JsonObject>> _consumers = new ArrayList<MessageConsumer<JsonObject>>();
private Map<String, IncomingLinkRef> _incomingLinkRefs = new HashMap<String, IncomingLinkRef>();
private Map<String, OutgoingLinkRef> _outgoingLinkRefs = new HashMap<String, OutgoingLinkRef>();
private Map<String, ServiceRef> _serviceRefs = new HashMap<String, ServiceRef>();
private Map<String, String> _replyToNotices = new HashMap<String, String>();
private final LinkRouter _linkBasedRouter;
private final MessageRouter _msgBasedRouter;
private final LinkManager _linkManager;
private final MessageTranslator _msgTranslator;
private final Verticle _parent;
public AMQPServiceImpl(Vertx vertx, AmqpServiceConfig config, Verticle parent) throws MessagingException {
_vertx = vertx;
_parent = parent;
_eb = _vertx.eventBus();
_config = config;
_msgTranslator = new MessageTranslator();
_msgBasedRouter = new MessageRouter(_config);
_linkBasedRouter = new LinkRouter();
_linkManager = new LinkManager(vertx, _config, this);
_replyToAddressPrefix = "amqp://" + _config.getInboundHost() + ":" + _config.getInboundPort();
_eb.consumer(config.getDefaultHandlerAddress(), this);
for (String handlerAddress : config.getHandlerAddressList()) {
_consumers.add(_eb.consumer(handlerAddress, this));
}
// TODO _config.print() // prints the current config at start time.
}
public void stopInternal() {
try {
_parent.stop(null);
} catch (Exception e) {
e.printStackTrace();
}
}
// ------------- AmqpService -----------------
@Override
public void start() {
// _linkManager.stop();
}
@Override
public void stop() {
_linkManager.stop();
}
@Override
public AMQPService establishIncomingLink(String amqpAddress, String eventbusAddress, String notificationAddress,
IncomingLinkOptions options, Handler<AsyncResult<String>> result) {
try {
LOG.info(
"Service method establishIncommingLink called with amqpAddress=%s, eventbusAddress=%s, notificationAddress=%s, options=%s",
amqpAddress, eventbusAddress, notificationAddress, options);
String id = _linkManager.createIncomingLink(amqpAddress, options);
_linkBasedRouter.addIncomingRoute(id, eventbusAddress);
_incomingLinkRefs.put(id,
new IncomingLinkRef(id, amqpAddress, eventbusAddress, notificationAddress, result));
LOG.info("Created incoming link from AMQP-message-soure to vertx-amqp-bridge '%s'. The link ref is '%s'",
amqpAddress, id);
result.handle(new DefaultAsyncResult<String>(id));
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<String>(e));
}
return this;
}
@Override
public AMQPService fetch(String incomingLinkRef, int messages, Handler<AsyncResult<Void>> result) {
try {
LOG.info("Service method fetch called with incomingLinkRef=%s, messages=%s", incomingLinkRef, messages);
_linkManager.setCredits(incomingLinkRef, messages);
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Error {%s}, when fetching messages from incoming link : %s.", e.getMessage(), incomingLinkRef), e
.getErrorCode())));
}
return this;
}
@Override
public AMQPService cancelIncomingLink(String incomingLinkRef, Handler<AsyncResult<Void>> result) {
try {
LOG.info("Service method cancelIncommingLink called with incomingLinkRef=%s", incomingLinkRef);
_linkManager.closeIncomingLink(incomingLinkRef);
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Error {%s}, when cancelling incoming link : %s.", e.getMessage(), incomingLinkRef), e
.getErrorCode())));
}
return this;
}
@Override
public AMQPService accept(String msgRef, Handler<AsyncResult<Void>> result) {
LOG.info("Service method accept called with msgRef=%s", msgRef);
return updateDelivery(msgRef, MessageDisposition.ACCEPTED, result);
}
@Override
public AMQPService reject(String msgRef, Handler<AsyncResult<Void>> result) {
LOG.info("Service method reject called with msgRef=%s", msgRef);
return updateDelivery(msgRef, MessageDisposition.REJECTED, result);
}
@Override
public AMQPService release(String msgRef, Handler<AsyncResult<Void>> result) {
LOG.info("Service method release called with msgRef=%s", msgRef);
return updateDelivery(msgRef, MessageDisposition.RELEASED, result);
}
AMQPService updateDelivery(String msgRef, MessageDisposition disposition, Handler<AsyncResult<Void>> result) {
try {
_linkManager.settleDelivery(msgRef, disposition);
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Error {%s}, when marking message={ref: %s} as %s", e.getMessage(), msgRef, disposition), e
.getErrorCode())));
}
return this;
}
@Override
public AMQPService establishOutgoingLink(String amqpAddress, String eventbusAddress, String notificationAddress,
OutgoingLinkOptions options, Handler<AsyncResult<String>> result) {
LOG.info(
"Service method establishOutgoingLink called with amqpAddress=%s, eventbusAddress=%s, notificationAddress=%s, options=%s",
amqpAddress, eventbusAddress, notificationAddress, options);
try {
String id = _linkManager.createOutgoingLink(amqpAddress, options);
_linkBasedRouter.addOutgoingRoute(eventbusAddress, id);
_eb.consumer(eventbusAddress, this);
_outgoingLinkRefs.put(id,
new OutgoingLinkRef(id, amqpAddress, eventbusAddress, notificationAddress, result));
LOG.info("Created outgoing link from vertx-amqp-bridge to AMQP-message-sink '%s'. The link ref is '%s'",
amqpAddress, id);
result.handle(new DefaultAsyncResult<String>(id));
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<String>(e));
}
return this;
}
@Override
public AMQPService cancelOutgoingLink(String outgoingLinkRef, Handler<AsyncResult<Void>> result) {
try {
LOG.info("Service method cancelOutgoingLink called with outgoingLinkRef=%s", outgoingLinkRef);
_linkManager.closeIncomingLink(outgoingLinkRef);
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} catch (MessagingException e) {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Error {%s}, when cancelling outgoing link : %s.", e.getMessage(), outgoingLinkRef), e
.getErrorCode())));
}
return this;
}
public AMQPService registerService(String eventbusAddress, String notificationAddress, ServiceOptions options,
Handler<AsyncResult<Void>> result) {
LOG.info("Service method registerService called with eventbusAddress=%s, options=%s", eventbusAddress, options);
if (_serviceRefs.containsKey(eventbusAddress)) {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Address '%s' is already in use by another service", eventbusAddress), ErrorCode.ALREADY_EXISTS)));
} else {
_serviceRefs.put(eventbusAddress,
new ServiceRef(eventbusAddress, notificationAddress, options.getInitialCapacity()));
result.handle(DefaultAsyncResult.VOID_SUCCESS);
LOG.info(format("Registered Service at address=%s with options=%s", eventbusAddress, options));
}
return this;
}
public AMQPService issueCredits(String linkId, int credits, Handler<AsyncResult<Void>> result) {
LOG.info("Service method issueCredits called with linkId=%s, credits=%s", linkId, credits);
try {
_linkManager.setCredits(linkId, credits);
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} catch (MessagingException e) {
LOG.warn(e, "Error issueing credits for link %s", linkId);
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Service : '%s', Error issueing credits for link %s", linkId), ErrorCode.INVALID_LINK_REF)));
}
return this;
}
@Fluent
public AMQPService unregisterService(String eventbusAddress, Handler<AsyncResult<Void>> result) {
LOG.info("Service method unregisterService called with eventbusAddress=%s", eventbusAddress);
if (_serviceRefs.containsKey(eventbusAddress)) {
ServiceRef service = _serviceRefs.remove(eventbusAddress);
for (String id : service._inLinks) {
try {
_linkManager.closeIncomingLink(id);
} catch (MessagingException e) {
LOG.warn(e, "UnregisterService : '%s', Error closing incoming link %s", eventbusAddress, id);
}
}
for (String id : service._outLinks) {
try {
_linkManager.closeOutgoingLink(id);
} catch (MessagingException e) {
LOG.warn(e, "UnregisterService : '%s', Error closing outgoing link %s", eventbusAddress, id);
}
}
result.handle(DefaultAsyncResult.VOID_SUCCESS);
} else {
result.handle(new DefaultAsyncResult<Void>(new MessagingException(format(
"Address '%s' doesn't match any registered service", eventbusAddress), ErrorCode.ADDRESS_NOT_FOUND)));
}
return this;
}
public AMQPService addInboundRoute(String pattern, String eventbusAddress) {
_msgBasedRouter.addInboundRoute(pattern, eventbusAddress);
return this;
}
public AMQPService removeInboundRoute(String pattern, String eventbusAddress) {
_msgBasedRouter.removeInboundRoute(pattern, eventbusAddress);
return this;
}
public AMQPService addOutboundRoute(String pattern, String amqpAddress) {
_msgBasedRouter.addOutboundRoute(pattern, amqpAddress);
return this;
}
public AMQPService removeOutboundRoute(String pattern, String amqpAddress) {
_msgBasedRouter.addOutboundRoute(pattern, amqpAddress);
return this;
}// ------------\ AmqpService -----------------
// -- Handler method for receiving messages from the event-bus -----------
@Override
public void handle(Message<JsonObject> vertxMsg) {
try {
LOG.debug(format("Received msg from Vert.x event bus : {address : %s, reply-to : %s, body : %s} ", vertxMsg.address(),
vertxMsg.replyAddress(), vertxMsg.body() == null ? "" : vertxMsg.body().encodePrettily()));
org.apache.qpid.proton.message.Message outMsg = _msgTranslator.convert(vertxMsg.body());
JsonObject inMsg = vertxMsg.body();
if (outMsg.getReplyTo() == null && vertxMsg.replyAddress() != null) {
outMsg.setReplyTo(_replyToAddressPrefix + "/" + vertxMsg.replyAddress());
_vertxReplyTo.put(vertxMsg.replyAddress(), vertxMsg);
}
// First attempt link routing (covers links created via Service API)
String linkId = _linkBasedRouter.routeOutgoing(vertxMsg.address());
if (linkId != null) {
try {
_linkManager.sendViaLink(linkId, outMsg, inMsg);
LogMsgHelper.logVertxMsgForLinkBasedRouting(LOG, vertxMsg, linkId);
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} sending to link %s", e.getErrorCode(), e.getMessage(),
linkId);
}
} else {
// Message based routing (routes added through static or dynamic
// config)
List<String> amqpAddressList = _msgBasedRouter.routeOutgoing(vertxMsg);
for (String amqpAddress : amqpAddressList) {
try {
_linkManager.sendViaAddress(amqpAddress, outMsg, inMsg);
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} sending to AMQP address %s", e.getErrorCode(),
e.getMessage(), amqpAddress);
}
}
LogMsgHelper.logVertxMsgForMsgBasedRouting(LOG, vertxMsg, amqpAddressList);
}
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} routing outbound", e.getErrorCode(), e.getMessage());
}
}// ------------- \ Event bus handler -----------
// ------------- LinkEventListener -----------
@Override
public void incomingLinkReady(String id, String address, boolean isFromInboundConnection) {
print("incomingLinkReady inbound=%s, id=%s , address=%s", isFromInboundConnection, id, address);
if (isFromInboundConnection) {
if (_serviceRefs.containsKey(address)) {
LOG.info("Mapping service address %s to incoming-link %s", address, id);
ServiceRef service = _serviceRefs.get(address);
String notificationAddress = service._notificationAddr;
_incomingLinkRefs.put(id, new IncomingLinkRef(id, null, null, notificationAddress, null));
_linkBasedRouter.addIncomingRoute(id, address);
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.incomingLinkOpened(id));
} else {
try {
_linkManager.setCredits(id, 1);
} catch (MessagingException e) {
LOG.warn(e, "Error setting credits for link %s", id);
}
}
} else {
if (_incomingLinkRefs.containsKey(id)) {
_incomingLinkRefs.get(id)._resultHandler.handle(new DefaultAsyncResult<String>(id));
LOG.info("Incoming Link '%s' is ready. Notifying handler", id);
}
}
}
@Override
public void incomingLinkFinal(String id, String address, boolean isFromInboundConnection) {
print("Incoming Link closed inbound=%s", isFromInboundConnection);
if (isFromInboundConnection) {
if (_serviceRefs.containsKey(address)) {
LOG.info("Notifying service %s incoming-link %s is closed", address, id);
ServiceRef service = _serviceRefs.get(address);
String notificationAddress = service._notificationAddr;
_incomingLinkRefs.remove(id);
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.incomingLinkClosed(id));
}
} else {
if (_incomingLinkRefs.containsKey(id)) {
IncomingLinkRef linkRef = _incomingLinkRefs.get(id);
String notificationAddress = linkRef._notificationAddr;
_incomingLinkRefs.remove(id);
LOG.info("Sending notification msg to '%s' : incoming-link %s closed", notificationAddress, id);
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.incomingLinkClosed(id));
}
}
}
@Override
public void outgoingLinkReady(String id, String address, boolean isFromInboundConnection) {
print("outgoingLinkReady inbound=%s, id=%s , address=%s", isFromInboundConnection, id, address);
if (isFromInboundConnection) {
if (_serviceRefs.containsKey(address)) {
LOG.info("Mapping service address %s to outgoing-link %s", address, id);
ServiceRef service = _serviceRefs.get(address);
String notificationAddress = service._notificationAddr;
_outgoingLinkRefs.put(id, new OutgoingLinkRef(id, null, null, notificationAddress, null));
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.outgoingLinkOpened(id));
} else {
LOG.info("Mapping address %s to outgoing-link %s", address, id);
_linkBasedRouter.addOutgoingRoute(address, id);
_eb.consumer(address, this);
_outgoingLinkRefs.put(id, new OutgoingLinkRef(id, null, null, null, null));
}
} else {
if (_outgoingLinkRefs.containsKey(id)) {
_outgoingLinkRefs.get(id)._resultHandler.handle(new DefaultAsyncResult<String>(id));
LOG.info("Outgoing Link '%s' is ready. Notifying handler", id);
}
}
}
@Override
public void outgoingLinkFinal(String id, String address, boolean isFromInboundConnection) {
print("Outgoing Link closed outbound=%s", isFromInboundConnection);
if (isFromInboundConnection) {
if (_serviceRefs.containsKey(address)) {
LOG.info("Notifying service %s outgoing-link %s closed", address, id);
ServiceRef service = _serviceRefs.get(address);
String notificationAddress = service._notificationAddr;
_outgoingLinkRefs.remove(id);
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.outgoingLinkClosed(id));
} else {
_linkBasedRouter.removeOutgoingRoute(id);
// TODO cancel event-bus consume.
}
} else {
if (_outgoingLinkRefs.containsKey(id)) {
OutgoingLinkRef linkRef = _outgoingLinkRefs.get(id);
String notificationAddress = linkRef._notificationAddr;
_outgoingLinkRefs.remove(id);
LOG.info("Sending notification msg to '%s' : outgoing-link %s closed", notificationAddress, id);
sendNotificatonMessage(notificationAddress, NotificationMessageFactory.outgoingLinkClosed(id));
}
}
}
@Override
public void deliveryUpdate(String id, String msgRef, DeliveryState state, MessageDisposition disp) {
print("Delivery update received for link=%s and msg-ref=%s", id, msgRef);
//print("_replyToNotices : %s", _replyToNotices);
if (_replyToNotices.containsKey(msgRef)) {
sendNotificatonMessage(_replyToNotices.remove(msgRef),
NotificationMessageFactory.deliveryState(msgRef, state, disp));
} else if (_outgoingLinkRefs.containsKey(id)) {
sendNotificatonMessage(_outgoingLinkRefs.get(id)._notificationAddr,
NotificationMessageFactory.deliveryState(msgRef, state, disp));
} else {
LOG.warn(
"Error : Delivery update received for link not in map. Details [msg-ref : '%s' tied to link-ref : '%s']",
msgRef, id);
}
}
@Override
public void message(String linkId, String linkAddress, ReliabilityMode reliability, InboundMessage inMsg) {
JsonObject outMsg;
try {
outMsg = _msgTranslator.convert(inMsg.getProtocolMessage());
} catch (MessageFormatException e) {
LOG.warn(e, "Error translating AMQP message %s ", inMsg);
return;
}
outMsg.put(INCOMING_MSG_REF, inMsg.getMsgRef());
outMsg.put(INCOMING_MSG_LINK_REF, linkId);
// Handle replyTo
if (handleReplyTo(linkAddress, inMsg, outMsg)) {
// it was a reply-to and has been handled. No further routing
// required.
return;
}
print("Received AMQP msg with reply-to : %s", inMsg.getReplyTo());
String vertxAddress = _linkBasedRouter.routeIncoming(linkId);
if (vertxAddress != null) {
print("xxxxxxxxxxx doing link based routing %s", _serviceRefs);
if (inMsg.getReplyTo() != null) {
String notificaitonAddress = null;
print("zzzzzzzzzzzzzzzzzzzzzzzzz service-refs %s", _serviceRefs);
if (_serviceRefs.containsKey(vertxAddress)) {
notificaitonAddress = _serviceRefs.get(vertxAddress)._notificationAddr;
} else if (_incomingLinkRefs.containsKey(linkId)) {
notificaitonAddress = _incomingLinkRefs.get(linkId)._notificationAddr;
}
_eb.send(vertxAddress, outMsg, new ReplyHandler(inMsg.getReplyTo(), notificaitonAddress));
} else {
_eb.send(vertxAddress, outMsg);
}
LogMsgHelper.logAmqpMsgForLinkBasedRouting(LOG, inMsg, linkId, vertxAddress);
} else {
List<String> addressList = _msgBasedRouter.routeIncoming(inMsg, linkAddress);
for (String address : addressList) {
if (inMsg.getReplyTo() != null) {
_eb.send(address, outMsg, new ReplyHandler(inMsg.getReplyTo(), null));
} else {
_eb.send(address, outMsg);
}
}
LogMsgHelper.logAmqpMsgForMsgBasedRouting(LOG, inMsg, linkId, addressList);
}
}
private boolean handleReplyTo(String linkAddress, InboundMessage inMsg, JsonObject outMsg) {
String replyToKey = null;
if (inMsg.getAddress() == null) {
replyToKey = linkAddress;
} else {
try {
ConnectionSettings settings = _linkManager.getConnectionSettings(inMsg.getAddress());
replyToKey = settings.getNode() != null ? settings.getNode() : settings.getHost();
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} parsing address field in AMQP message", e.getErrorCode(),
e.getMessage());
}
}
if (_vertxReplyTo.containsKey(replyToKey)) {
LogMsgHelper.logInboundReplyTo(LOG, inMsg, replyToKey);
try {
Message<JsonObject> request = _vertxReplyTo.remove(replyToKey);
request.reply(outMsg);
request = null;
return true;
} catch (Exception e) {
LOG.warn(e, "Error {msg='%s'} replying to vertx msg", e.getMessage());
}
}
return false;
}
@Override
public void outgoingLinkCreditGiven(String id, int credits) {
if (_outgoingLinkRefs.containsKey(id)) {
if (_outgoingLinkRefs.get(id)._notificationAddr != null) {
sendNotificatonMessage(_outgoingLinkRefs.get(id)._notificationAddr,
NotificationMessageFactory.credit(id, credits));
}
} else {
LOG.warn("Error : Credit received for link not in map. Details [link-ref : '%s']", id);
}
}// ----------- \ LinkEventListener ------------
private void sendNotificatonMessage(String address, JsonObject msg) {
if (address != null) {
_eb.send(address, msg);
}
}
// ---------- Helper classes
// TODO need to handle replyTo more efficiently.
class ReplyHandler implements Handler<AsyncResult<Message<JsonObject>>> {
String _replyTo;
String _notificationAddr;
ReplyHandler(String replyTo, String notificationAddr) {
_replyTo = replyTo;
_notificationAddr = notificationAddr;
}
@Override
public void handle(AsyncResult<Message<JsonObject>> result) {
Message<JsonObject> msg = result.result();
try {
print("Reply received from Vert.x event-bus %s ", msg.body() == null ? "" : msg.body().encodePrettily());
LogMsgHelper.logOutboundReplyTo(LOG, msg, _replyTo);
org.apache.qpid.proton.message.Message out = _msgTranslator.convert(msg.body());
String linkId = _linkBasedRouter.routeOutgoing(Functions.extractDestination(_replyTo));
print("_replyTo=%s, linkId=%s", _replyTo, linkId);
if (linkId != null) {
try {
_linkManager.sendViaLink(linkId, out, msg.body());
LOG.info(" vertx-amqp-service is hosting reply-to destination '%s'", _replyTo);
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} sending to link %s", e.getErrorCode(), e.getMessage(),
linkId);
}
} else {
_linkManager.sendViaAddress(_replyTo, out, msg.body());
}
if (_notificationAddr != null && msg.body().containsKey(AMQPService.OUTGOING_MSG_REF)) {
print("Adding the reply-to:notification pair {%s : %s}", msg.body().getString(AMQPService.OUTGOING_MSG_REF), _notificationAddr);
_replyToNotices.put(msg.body().getString(AMQPService.OUTGOING_MSG_REF), _notificationAddr);
}
} catch (MessagingException e) {
LOG.warn(e, "Error {code=%s, msg='%s'} handling reply", e.getErrorCode(), e.getMessage());
}
}
}
class IncomingLinkRef {
final String _id;
final String _amqpAddr;
final String _ebAddr;
final String _notificationAddr;
final Handler<AsyncResult<String>> _resultHandler;
IncomingLinkRef(String id, String amqpAddr, String ebAddr, String notificationAddr,
Handler<AsyncResult<String>> resultHandler) {
_id = id;
_amqpAddr = amqpAddr;
_ebAddr = ebAddr;
_notificationAddr = notificationAddr;
_resultHandler = resultHandler;
}
}
class OutgoingLinkRef {
final String _id;
final String _amqpAddr;
final String _ebAddr;
final String _notificationAddr;
final Handler<AsyncResult<String>> _resultHandler;
OutgoingLinkRef(String id, String amqpAddr, String ebAddr, String notificationAddr,
Handler<AsyncResult<String>> resultHandler) {
_id = id;
_amqpAddr = amqpAddr;
_ebAddr = ebAddr;
_notificationAddr = notificationAddr;
_resultHandler = resultHandler;
}
}
class ServiceRef {
final String _serviceAddr;
final String _notificationAddr;
final List<String> _inLinks = new ArrayList<String>();
final List<String> _outLinks = new ArrayList<String>();
ServiceRef(String serviceAddr, String notificationAddress, int initialCapacity) {
_serviceAddr = serviceAddr;
_notificationAddr = notificationAddress;
}
void addIncomingLink(String linkId) {
_inLinks.add(linkId);
}
void removeIncomingLink(String linkId) {
_inLinks.remove(linkId);
}
void addOutgoingLink(String linkId) {
_outLinks.add(linkId);
}
void removeOutgoingLink(String linkId) {
_outLinks.remove(linkId);
}
}
}