use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class TransactionWorkMessage method readWork.
public void readWork(DataInputStream dis) throws IOException, BrokerException {
message = new Packet(false);
message.generateTimestamp(false);
message.generateSequenceNumber(false);
message.readPacket(dis);
int numStoredInterests = dis.readInt();
storedInterests = new ConsumerUID[numStoredInterests];
for (int j = 0; j < numStoredInterests; j++) {
long cuid = dis.readLong();
storedInterests[j] = new ConsumerUID(cuid);
}
// Make sure dest exists; auto-create if possible
// this is because we will need to add messages to this
// destination
destUID = DestinationUID.getUID(message.getDestination(), message.getIsQueue());
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class AckHandler method handleAcks.
public void handleAcks(IMQConnection con, SysMessageID[] ids, ConsumerUID[] cids, boolean ackack, List cleanList) throws BrokerException, IOException {
// we could eliminate on of the lookups
for (int i = 0; i < ids.length; i++) {
if (DEBUG) {
logger.log(logger.INFO, "handleAcks[" + i + ", " + ids.length + "]:sysid=" + ids[i] + ", cid=" + cids[i] + ", on connection " + con);
}
Session s = Session.getSession(cids[i]);
if (s == null) {
// consumer does not have session
Consumer c = Consumer.getConsumer(cids[i]);
if (c == null) {
if (!con.isValid() || con.isBeingDestroyed()) {
if (DEBUG) {
logger.log(logger.INFO, "Received ack for consumer " + cids[i] + " on closing connection " + con);
}
continue;
}
if (BrokerStateHandler.isShutdownStarted()) {
throw new BrokerException(br.I_ACK_FAILED_BROKER_SHUTDOWN);
}
throw new BrokerException(br.getKString(br.I_ACK_FAILED_NO_CONSUMER, cids[i]), Status.NOT_FOUND);
} else if (c.getConsumerUID().getBrokerAddress() != Globals.getClusterBroadcast().getMyAddress()) {
// remote consumer
PacketReference ref = DL.get(null, ids[i]);
if (ref == null) {
BrokerException bex = new BrokerException(br.getKString(br.I_ACK_FAILED_MESSAGE_REF_GONE, ids[i]) + "[" + cids[i] + "]", Status.GONE);
bex.setRemoteConsumerUIDs(String.valueOf(cids[i].longValue()));
bex.setRemote(true);
throw bex;
}
ConsumerUID cuid = c.getConsumerUID();
// but who knows if that will change
if (ref.acknowledged(cuid, c.getStoredConsumerUID(), !cuid.isDupsOK(), true, ackack)) {
cleanList.add(ref);
}
} else {
String emsg = br.getKString(br.I_LOCAL_CONSUMER_ACK_FAILED_NO_SESSION, "[" + ids[i] + ", " + cids[i] + "]", cids[i]);
logger.log(Logger.WARNING, emsg);
throw new BrokerException(emsg);
}
} else {
if (fi.FAULT_INJECTION) {
PacketReference ref = DL.get(null, ids[i]);
if (ref != null && !ref.getDestination().isAdmin() && !ref.getDestination().isInternal()) {
if (fi.checkFault(fi.FAULT_ACK_MSG_1_5, null)) {
fi.unsetFault(fi.FAULT_ACK_MSG_1_5);
BrokerException bex = new BrokerException("FAULT:" + fi.FAULT_ACK_MSG_1_5, Status.GONE);
bex.setRemoteConsumerUIDs(String.valueOf(cids[i].longValue()));
bex.setRemote(true);
throw bex;
}
}
}
PacketReference ref = (PacketReference) s.ackMessage(cids[i], ids[i], ackack);
try {
s.postAckMessage(cids[i], ids[i], ackack);
} finally {
if (ref != null) {
cleanList.add(ref);
}
}
}
}
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class GetDurablesHandler method handle.
/**
* Handle the incomming administration message.
*
* @param con The Connection the message came in on.
* @param cmd_msg The administration message
* @param cmd_props The properties from the administration message
*/
@Override
public boolean handle(IMQConnection con, Packet cmd_msg, Hashtable cmd_props) {
if (DEBUG) {
logger.log(Logger.DEBUG, this.getClass().getName() + ": " + cmd_props);
}
String destination = (String) cmd_props.get(MessageType.JMQ_DESTINATION);
// Send reply
Packet reply = new Packet(con.useDirectBuffers());
reply.setPacketType(PacketType.OBJECT_MESSAGE);
int status = Status.OK;
Vector v = null;
String err = null;
try {
DestinationUID duid = null;
if (destination != null) {
duid = DestinationUID.getUID(destination, false);
}
Set s = Subscription.getAllSubscriptions(duid);
v = new Vector();
Iterator itr = s.iterator();
while (itr.hasNext()) {
Subscription sub = (Subscription) itr.next();
DurableInfo di = new DurableInfo();
di.isDurable = sub.isDurable();
di.isShared = sub.getShared();
di.isJMSShared = sub.getJMSShared();
if (di.isDurable) {
di.name = sub.getDurableName();
} else if (di.isJMSShared) {
di.name = sub.getNDSubscriptionName();
}
di.clientID = sub.getClientID();
di.isActive = sub.isActive();
di.uidString = String.valueOf(sub.getConsumerUID().longValue());
List children = sub.getChildConsumers();
di.activeCount = children.size();
di.activeConsumers = new LinkedHashMap<>();
Iterator itr1 = children.iterator();
while (itr1.hasNext()) {
Consumer c = (Consumer) itr1.next();
ConsumerInfo cinfo = new ConsumerInfo();
cinfo.connection = new ConnectionInfo();
cinfo.connection.uuid = c.getConsumerUID().getConnectionUID().longValue();
cinfo.uidString = String.valueOf(c.getConsumerUID().longValue());
ConsumerUID uid = c.getStoredConsumerUID();
if (uid != null) {
cinfo.subuidString = String.valueOf(uid.longValue());
}
BrokerAddress addr = c.getConsumerUID().getBrokerAddress();
if (addr != null) {
cinfo.brokerAddressShortString = addr.getMQAddress().getHostAddressNPort() + (addr.getBrokerID() == null ? "" : "[" + addr.getBrokerID() + "]");
}
di.activeConsumers.put(cinfo.uidString, cinfo);
}
di.nMessages = sub.numInProcessMsgs();
di.consumer = new ConsumerInfo();
// Ok, I'm not setting id because it really should be an int, maybe later
di.consumer.destination = sub.getDestinationUID().getName();
di.consumer.type = DestType.DEST_TYPE_TOPIC;
di.consumer.selector = sub.getSelectorStr();
// not bothering with the connection this time either
di.consumer.connection = null;
v.add(di);
}
} catch (BrokerException ex) {
err = ex.getMessage();
status = ex.getStatusCode();
}
setProperties(reply, MessageType.GET_DURABLES_REPLY, status, err);
setBodyObject(reply, v);
parent.sendReply(con, cmd_msg, reply);
return true;
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class BrokerConsumers method acknowledgeMessageFromRemote2P.
public void acknowledgeMessageFromRemote2P(int ackType, SysMessageID[] sysids, com.sun.messaging.jmq.jmsserver.core.ConsumerUID[] cuids, Map optionalProps, Long txnID, com.sun.messaging.jmq.jmsserver.core.BrokerAddress txnHomeBroker) throws BrokerException {
if (txnID == null) {
throw new BrokerException("Internal Error: call with null txnID");
}
// handle 2-phase remote ack
TransactionUID tid = new TransactionUID(txnID.longValue());
if (ackType == ClusterBroadcast.MSG_PREPARE) {
PartitionedStore refpstore = null;
TransactionAcknowledgement ta = null;
ArrayList<TransactionAcknowledgement> tltas = null;
TransactionAcknowledgement[] tas = null;
HashMap<TransactionList, ArrayList<TransactionAcknowledgement>> tltasmap = new HashMap<>();
TransactionList tl = null;
AckEntry entry = null, value = null;
StringBuilder dbuf = new StringBuilder();
AckEntryNotFoundException ae = null;
synchronized (deliveredMessages) {
for (int i = 0; i < sysids.length; i++) {
entry = new AckEntry(sysids[i], cuids[i], null);
value = (AckEntry) deliveredMessages.get(entry);
if (value == null) {
// XXX
String emsg = "[" + sysids[i] + ":" + cuids[i] + "]TID=" + tid + " not found, maybe rerouted";
if (ae == null) {
ae = new AckEntryNotFoundException(emsg);
}
ae.addAckEntry(sysids[i], cuids[i]);
logger.log(logger.WARNING, "[" + sysids[i] + ":" + cuids[i] + "] not found for preparing remote transaction " + tid + ", maybe rerouted");
continue;
}
if (value.getTUID() != null) {
String emsg = "[" + sysids[i] + ":" + cuids[i] + "]TID=" + tid + " has been rerouted";
if (ae == null) {
ae = new AckEntryNotFoundException(emsg);
}
ae.addAckEntry(sysids[i], cuids[i]);
logger.log(logger.WARNING, "[" + sysids[i] + ":" + cuids[i] + "] for preparing remote transaction " + tid + " conflict with transaction " + value.getTUID());
continue;
}
PacketReference ref = value.getReference();
if (ref == null) {
deliveredMessages.remove(entry);
String emsg = "Unable to prepare [" + sysids[i] + ":" + cuids[i] + "]TID=" + tid + " because the message has been removed";
if (ae == null) {
ae = new AckEntryNotFoundException(emsg);
}
ae.addAckEntry(sysids[i], cuids[i]);
logger.log(logger.WARNING, emsg);
continue;
}
com.sun.messaging.jmq.jmsserver.core.ConsumerUID scuid = value.getStoredConsumerUID();
ta = new TransactionAcknowledgement(sysids[i], cuids[i], scuid);
if (!scuid.shouldStore() || !ref.isPersistent()) {
ta.setShouldStore(false);
}
if (!Globals.getDestinationList().isPartitionMode()) {
TransactionList[] tls = DL.getTransactionList(Globals.getStore().getPrimaryPartition());
tl = tls[0];
} else {
refpstore = ref.getPartitionedStore();
TransactionList[] tls = Globals.getDestinationList().getTransactionList(refpstore);
tl = tls[0];
if (tl == null) {
deliveredMessages.remove(entry);
String emsg = "Unable to prepare [" + sysids[i] + ":" + cuids[i] + "]TID=" + tid + " because transaction list for partition " + refpstore + " not found";
if (ae == null) {
ae = new AckEntryNotFoundException(emsg);
}
ae.addAckEntry(sysids[i], cuids[i]);
logger.log(logger.WARNING, emsg);
continue;
}
}
tltas = tltasmap.get(tl);
if (tltas == null) {
tltas = new ArrayList<>();
tltasmap.put(tl, tltas);
}
tltas.add(ta);
if (getDEBUG()) {
dbuf.append("\n\t[" + ta + "]" + tl);
}
}
if (ae != null) {
throw ae;
}
Iterator<Map.Entry<TransactionList, ArrayList<TransactionAcknowledgement>>> itr = tltasmap.entrySet().iterator();
Map.Entry<TransactionList, ArrayList<TransactionAcknowledgement>> pair = null;
while (itr.hasNext()) {
pair = itr.next();
tl = pair.getKey();
tltas = pair.getValue();
tas = tltas.toArray(new TransactionAcknowledgement[tltas.size()]);
TransactionState ts = new TransactionState(AutoRollbackType.NOT_PREPARED, 0L, true);
ts.setState(TransactionState.PREPARED);
if (getDEBUG()) {
logger.log(logger.INFO, "Preparing remote transaction " + tid + " for [" + tltas + "]" + tl + " from " + txnHomeBroker);
}
tl.logRemoteTransaction(tid, ts, tas, txnHomeBroker, false, true, true);
}
for (int i = 0; i < sysids.length; i++) {
entry = new AckEntry(sysids[i], cuids[i], null);
value = (AckEntry) deliveredMessages.get(entry);
value.setTUID(tid);
}
}
Iterator<TransactionList> itr = tltasmap.keySet().iterator();
while (itr.hasNext()) {
tl = itr.next();
tl.pendingStartedForRemotePreparedTransaction(tid);
}
notifyPendingCheckTimer();
if (getDEBUG()) {
logger.log(logger.INFO, "Prepared remote transaction " + tid + " from " + txnHomeBroker + dbuf.toString());
}
return;
}
if (ackType == ClusterBroadcast.MSG_ROLLEDBACK) {
if (getDEBUG()) {
logger.log(logger.INFO, "Rolling back remote transaction " + tid + " from " + txnHomeBroker);
}
List<Object[]> list = TransactionList.getTransListsAndRemoteTranStates(tid);
if (list == null) {
if (getDEBUG()) {
logger.log(logger.INFO, "Rolling back non-prepared remote transaction " + tid + " from " + txnHomeBroker);
}
List<AckEntry> entries = null;
synchronized (deliveredMessages) {
entries = getPendingConsumerUID(tid);
Iterator<AckEntry> itr = entries.iterator();
AckEntry e = null;
while (itr.hasNext()) {
e = itr.next();
if (deliveredMessages.get(e) == null) {
itr.remove();
continue;
}
if (consumers.get(e.getConsumerUID()) != null) {
itr.remove();
continue;
}
}
if (e != null) {
deliveredMessages.remove(e);
cleanupPendingConsumerUID(e.getConsumerUID(), e.getSysMessageID());
}
}
if (entries.size() == 0) {
logger.log(logger.INFO, br.getKString(br.I_ROLLBACK_REMOTE_TXN_NOT_FOUND, tid, txnHomeBroker));
return;
}
Iterator<AckEntry> itr = entries.iterator();
while (itr.hasNext()) {
AckEntry e = itr.next();
SysMessageID sysid = e.getSysMessageID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID cuid = e.getConsumerUID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID suid = e.getStoredConsumerUID();
if (suid == null) {
suid = cuid;
}
// PART
PacketReference ref = DL.get(null, sysid);
if (ref == null) {
if (getDEBUG()) {
logger.log(logger.INFO, "[" + sysid + ":" + cuid + "] reference not found in rolling back remote non-prepared transaction " + tid);
}
continue;
}
ref.removeInDelivery(suid);
ref.getDestination().forwardOrphanMessage(ref, suid);
}
return;
}
// if list == null
TransactionList tl = null;
Object[] oo = null;
for (int li = 0; li < list.size(); li++) {
oo = list.get(li);
tl = (TransactionList) oo[0];
if (!tl.updateRemoteTransactionState(tid, TransactionState.ROLLEDBACK, false, false, true)) {
return;
}
if (tl.getRecoveryRemoteTransactionAcks(tid) != null) {
rollbackRecoveryRemoteTransaction(tl, tid, txnHomeBroker);
}
RemoteTransactionAckEntry tae = tl.getRemoteTransactionAcks(tid);
if (tae == null) {
logger.log(logger.INFO, Globals.getBrokerResources().getKString(BrokerResources.I_NO_NONRECOVERY_TXNACK_TO_ROLLBACK, tid));
} else if (tae.processed()) {
logger.log(logger.INFO, Globals.getBrokerResources().getKString(BrokerResources.I_NO_MORE_TXNACK_TO_ROLLBACK, tid));
} else if (!tae.isLocalRemote()) {
TransactionAcknowledgement[] tas = tae.getAcks();
Set s = new LinkedHashSet();
AckEntry entry = null, value = null;
for (int i = 0; i < tas.length; i++) {
SysMessageID sysid = tas[i].getSysMessageID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID uid = tas[i].getConsumerUID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID suid = tas[i].getStoredConsumerUID();
if (suid == null) {
suid = uid;
}
synchronized (deliveredMessages) {
entry = new AckEntry(sysid, uid, null);
value = (AckEntry) deliveredMessages.get(entry);
if (value == null) {
if (getDEBUG()) {
logger.log(logger.INFO, "[" + sysid + ":" + uid + "] not found in rolling back remote transaction " + tid);
}
continue;
}
if (value.getTUID() == null || !value.getTUID().equals(tid)) {
if (getDEBUG()) {
logger.log(logger.INFO, "[" + sysid + ":" + uid + "] with TUID=" + value.getTUID() + ", in confict for rolling back remote transaction " + tid);
}
continue;
}
if (consumers.get(uid) == null) {
deliveredMessages.remove(entry);
cleanupPendingConsumerUID(uid, sysid);
s.add(tas[i]);
} else {
value.setTUID(null);
}
}
}
Iterator itr = s.iterator();
while (itr.hasNext()) {
TransactionAcknowledgement ta = (TransactionAcknowledgement) itr.next();
SysMessageID sysid = ta.getSysMessageID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID cuid = ta.getConsumerUID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID suid = ta.getStoredConsumerUID();
if (suid == null) {
suid = cuid;
}
// PART
PacketReference ref = DL.get(null, sysid);
if (ref == null) {
if (getDEBUG()) {
logger.log(logger.INFO, "[" + sysid + ":" + cuid + "] reference not found in rolling back remote transaction " + tid);
}
continue;
}
ref.removeInDelivery(suid);
ref.getDestination().forwardOrphanMessage(ref, suid);
}
}
try {
tl.removeRemoteTransactionAck(tid);
} catch (Exception e) {
logger.log(logger.WARNING, "Unable to remove transaction ack for rolledback transaction " + tid + ": " + e.getMessage());
}
try {
tl.removeRemoteTransactionID(tid, true);
} catch (Exception e) {
logger.log(logger.WARNING, "Unable to remove rolledback remote transaction " + tid + ": " + e.getMessage());
}
}
// for
return;
}
int cLogRecordCount = 0;
ArrayList cLogDstList = null;
ArrayList cLogMsgList = null;
ArrayList cLogIntList = null;
if (ackType == ClusterBroadcast.MSG_ACKNOWLEDGED) {
if (getDEBUG()) {
logger.log(logger.INFO, "Committing remote transaction " + tid + " from " + txnHomeBroker);
}
List<Object[]> list = TransactionList.getTransListsAndRemoteTranStates(tid);
if (list == null) {
throw new BrokerException("Committing remote transaction " + tid + " not found", Status.NOT_FOUND);
}
TransactionList tl = null;
Object[] oo = null;
for (int li = 0; li < list.size(); li++) {
oo = list.get(li);
tl = (TransactionList) oo[0];
if (!tl.updateRemoteTransactionState(tid, TransactionState.COMMITTED, (sysids == null), true, true)) {
if (getDEBUG()) {
logger.log(logger.INFO, "Remote transaction " + tid + " already committed, from " + txnHomeBroker);
}
continue;
}
boolean done = true;
if (tl.getRecoveryRemoteTransactionAcks(tid) != null) {
done = commitRecoveryRemoteTransaction(tl, tid, txnHomeBroker);
}
RemoteTransactionAckEntry tae = tl.getRemoteTransactionAcks(tid);
if (tae == null) {
logger.log(logger.INFO, "No non-recovery transaction acks to process for committing remote transaction " + tid);
} else if (tae.processed()) {
logger.log(logger.INFO, "No more transaction acks to process for committing remote transaction " + tid);
} else if (!tae.isLocalRemote()) {
boolean found = false;
TransactionAcknowledgement[] tas = tae.getAcks();
for (int i = 0; i < tas.length; i++) {
SysMessageID sysid = tas[i].getSysMessageID();
com.sun.messaging.jmq.jmsserver.core.ConsumerUID cuid = tas[i].getConsumerUID();
if (sysids != null && !found) {
if (sysid.equals(sysids[0]) && cuid.equals(cuids[0])) {
found = true;
}
}
String dstName = null;
if (Globals.txnLogEnabled()) {
if (cLogDstList == null) {
cLogDstList = new ArrayList();
cLogMsgList = new ArrayList();
cLogIntList = new ArrayList();
}
PacketReference ref = DL.get(null, sysid);
if (ref != null && !ref.isDestroyed() && !ref.isInvalid()) {
Destination[] ds = DL.getDestination(ref.getPartitionedStore(), ref.getDestinationUID());
Destination dst = ds[0];
dstName = dst.getUniqueName();
}
}
if (acknowledgeMessageFromRemote(ackType, sysid, cuid, optionalProps)) {
if (dstName != null) {
// keep track for consumer txn log
com.sun.messaging.jmq.jmsserver.core.ConsumerUID suid = tas[i].getStoredConsumerUID();
if (suid == null) {
suid = cuid;
}
cLogRecordCount++;
cLogDstList.add(dstName);
cLogMsgList.add(sysid);
cLogIntList.add(suid);
}
} else {
done = false;
}
}
// notify that message acks have been written to store
if (Globals.isNewTxnLogEnabled()) {
if (DL.isPartitionMode()) {
throw new BrokerException("Partition mode not supported if newTxnLog enabled");
}
((TxnLoggingStore) Globals.getStore().getPrimaryPartition()).loggedCommitWrittenToMessageStore(tid, BaseTransaction.REMOTE_TRANSACTION_TYPE);
}
if (sysids != null && !found) {
logger.log(logger.ERROR, "Internal Error: [" + sysids[0] + ":" + cuids[0] + "] not found in remote transaction " + tid);
done = false;
}
}
// tae != null
if (done) {
try {
tl.removeRemoteTransactionAck(tid);
} catch (Exception e) {
logger.logStack(logger.WARNING, "Unable to remove transaction ack for committed remote transaction " + tid, e);
}
try {
tl.removeRemoteTransactionID(tid, true);
} catch (Exception e) {
logger.logStack(logger.WARNING, "Unable to remove committed remote transaction " + tid, e);
}
} else if (Globals.getHAEnabled()) {
throw new BrokerException("Remote transaction processing incomplete, TUID=" + tid);
}
}
// log to txn log if enabled
try {
if (Globals.txnLogEnabled() && (cLogRecordCount > 0)) {
// Log all acks for consuming txn
ByteArrayOutputStream bos = new ByteArrayOutputStream((cLogRecordCount * (32 + SysMessageID.ID_SIZE + 8)) + 12);
DataOutputStream dos = new DataOutputStream(bos);
// Transaction ID (8 bytes)
dos.writeLong(tid.longValue());
// Number of acks (4 bytes)
dos.writeInt(cLogRecordCount);
for (int i = 0; i < cLogRecordCount; i++) {
String dst = (String) cLogDstList.get(i);
// Destination
dos.writeUTF(dst);
SysMessageID sysid = (SysMessageID) cLogMsgList.get(i);
// SysMessageID
sysid.writeID(dos);
long intid = ((com.sun.messaging.jmq.jmsserver.core.ConsumerUID) cLogIntList.get(i)).longValue();
// ConsumerUID
dos.writeLong(intid);
}
dos.close();
bos.close();
// PART
((TxnLoggingStore) Globals.getStore().getPrimaryPartition()).logTxn(TransactionLogType.CONSUME_TRANSACTION, bos.toByteArray());
}
} catch (IOException ex) {
logger.logStack(Logger.ERROR, Globals.getBrokerResources().E_INTERNAL_BROKER_ERROR, "Got exception while writing to transaction log", ex);
throw new BrokerException("Internal Error: Got exception while writing to transaction log", ex);
}
return;
}
throw new BrokerException("acknowledgeMessageFromRemotePriv:Unexpected ack type:" + ackType);
}
use of com.sun.messaging.jmq.jmsserver.core.ConsumerUID in project openmq by eclipse-ee4j.
the class BrokerConsumers method updateConsumed.
private void updateConsumed(AckEntry e, Integer deliverCnt, boolean cleanup) {
int cnt = deliverCnt.intValue();
if (cnt <= 0) {
cnt = 1;
}
PacketReference pr = e.getReference();
if (pr != null && !e.hasMarkConsumed()) {
ConsumerUID cuid = e.getConsumerUID();
ConsumerUID suid = e.getStoredConsumerUID();
try {
pr.updateForJMSXDeliveryCount(suid, cnt, !cleanup);
e.markConsumed();
} catch (Exception ex) {
Object[] args = { "[" + pr + "," + suid + "]", cuid, ex.getMessage() };
logger.log(Logger.WARNING, Globals.getBrokerResources().getKString(BrokerResources.W_UNABLE_UPDATE_REF_STATE_ON_CLOSE_CONSUMER, args) + (cleanup ? "[RC]" : "[R]"), ex);
}
}
}
Aggregations