/*
* 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.protocol;
import io.vertx.ext.amqp.impl.ConnectionSettings;
import io.vertx.ext.amqp.impl.CreditMode;
import io.vertx.ext.amqp.MessagingException;
import io.vertx.ext.amqp.ReliabilityMode;
import org.apache.qpid.proton.Proton;
import org.apache.qpid.proton.amqp.transport.ReceiverSettleMode;
import org.apache.qpid.proton.amqp.transport.SenderSettleMode;
import org.apache.qpid.proton.engine.*;
import org.apache.qpid.proton.engine.Link;
import org.apache.qpid.proton.message.Message;
/**
* A Connection coupled with a session to simplify the RouterImpl.
*/
class ManagedConnection extends ConnectionImpl {
private final org.apache.qpid.proton.engine.Session _protonSession;
private ManagedSession _session;
private AmqpEventListener eventListener;
ManagedConnection(ConnectionSettings settings, AmqpEventListener handler, boolean inbound) {
super(settings, null, inbound);
eventListener = handler;
_protonSession = protonConnection.session();
_session = new ManagedSession(this, _protonSession);
_protonSession.open();
}
@Override
protected void processEvents() {
protonConnection.collect(_collector);
Event event = _collector.peek();
while (event != null) {
switch (event.getType()) {
case CONNECTION_REMOTE_OPEN:
eventListener.onConnectionOpen(this);
break;
case CONNECTION_FINAL:
eventListener.onConnectionClosed(this);
break;
case SESSION_REMOTE_OPEN:
SessionImpl ssn;
org.apache.qpid.proton.engine.Session amqpSsn = event.getSession();
if (amqpSsn.getContext() != null) {
ssn = (SessionImpl) amqpSsn.getContext();
} else {
ssn = new SessionImpl(this, amqpSsn);
amqpSsn.setContext(ssn);
event.getSession().open();
}
eventListener.onSessionOpen(ssn);
break;
case SESSION_FINAL:
ssn = (SessionImpl) event.getSession().getContext();
eventListener.onSessionClosed(ssn);
break;
case LINK_REMOTE_OPEN:
Link link = event.getLink();
if (link instanceof Receiver) {
IncomingLinkImpl inboundLink;
if (link.getContext() != null) {
inboundLink = (IncomingLinkImpl) link.getContext();
} else {
inboundLink = new IncomingLinkImpl(_session, link.getRemoteTarget().getAddress(), link,
ReliabilityMode.AT_LEAST_ONCE, CreditMode.AUTO);
link.setContext(inboundLink);
inboundLink.init();
}
eventListener.onIncomingLinkOpen(inboundLink);
} else {
OutgoingLinkImpl outboundLink;
if (link.getContext() != null) {
outboundLink = (OutgoingLinkImpl) link.getContext();
} else {
outboundLink = new OutgoingLinkImpl(_session, link.getRemoteSource().getAddress(), link);
link.setContext(outboundLink);
outboundLink.init();
}
eventListener.onOutgoingLinkOpen(outboundLink);
}
break;
case LINK_FLOW:
link = event.getLink();
if (link instanceof Sender) {
OutgoingLinkImpl outboundLink = (OutgoingLinkImpl) link.getContext();
eventListener.onOutgoingLinkCredit(outboundLink, link.getCredit());
}
break;
case LINK_FINAL:
link = event.getLink();
if (link instanceof Receiver) {
IncomingLinkImpl inboundLink = (IncomingLinkImpl) link.getContext();
eventListener.onIncomingLinkClosed(inboundLink);
} else {
OutgoingLinkImpl outboundLink = (OutgoingLinkImpl) link.getContext();
eventListener.onOutgoingLinkClosed(outboundLink);
}
break;
case TRANSPORT:
// TODO
break;
case DELIVERY:
onDelivery(event.getDelivery());
break;
default:
break;
}
_collector.pop();
event = _collector.peek();
}
}
@Override
void onDelivery(Delivery d) {
Link link = d.getLink();
if (link instanceof Receiver) {
if (d.isReadable() && !d.isPartial()) {
Receiver receiver = (Receiver) link;
byte[] bytes = new byte[d.pending()];
int read = receiver.recv(bytes, 0, bytes.length);
Message pMsg = Proton.message();
pMsg.decode(bytes, 0, read);
receiver.advance();
IncomingLinkImpl inLink = (IncomingLinkImpl) link.getContext();
SessionImpl ssn = inLink.getSession();
InboundMessage msg = new InboundMessage(ssn.getID(), d.getTag(), ssn.getNextIncommingSequence(),
d.isSettled(), pMsg);
if (link.getSenderSettleMode() != SenderSettleMode.SETTLED) {
ssn.addUnsettled(msg.getSequence(), d);
}
eventListener.onMessage(inLink, msg);
} else if (d.isUpdated() && d.isSettled()) {
if (link.getReceiverSettleMode() == ReceiverSettleMode.SECOND) {
d.settle();
}
}
} else {
if (d.remotelySettled()) {
TrackerImpl tracker = (TrackerImpl) d.getContext();
tracker.setDisposition(d.getRemoteState());
tracker.markSettled();
eventListener.onSettled((OutgoingLinkImpl) link.getContext(), tracker);
}
}
}
public OutgoingLinkImpl createOutboundLink(String address, ReliabilityMode mode) throws MessagingException {
OutgoingLinkImpl link = (OutgoingLinkImpl) _session.createOutboundLink(address, mode);
link.init();
write();
return link;
}
public IncomingLinkImpl createInboundLink(String address, ReliabilityMode receiverMode, CreditMode creditMode)
throws MessagingException {
IncomingLinkImpl link = (IncomingLinkImpl) _session.createInboundLink(address, receiverMode, creditMode);
link.init();
write();
return link;
}
}