Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2010-2024 60East Technologies Inc., All Rights Reserved.
//
// This computer software is owned by 60East Technologies Inc. and is
// protected by U.S. copyright laws and other laws and by international
// treaties. This computer software is furnished by 60East Technologies
// Inc. pursuant to a written license agreement and may be used, copied,
// transmitted, and stored only in accordance with the terms of such
// license agreement and with the inclusion of the above copyright notice.
// This computer software or any other copies thereof may not be provided
// or otherwise made available to any other person.
//
// U.S. Government Restricted Rights. This computer software: (a) was
// developed at private expense and is in all respects the proprietary
// information of 60East Technologies Inc.; (b) was not developed with
// government funds; (c) is a trade secret of 60East Technologies Inc.
// for all purposes of the Freedom of Information Act; and (d) is a
// commercial item and thus, pursuant to Section 12.212 of the Federal
// Acquisition Regulations (FAR) and DFAR Supplement Section 227.7202,
// Government's use, duplication or disclosure of the computer software
// is subject to the restrictions set forth by 60East Technologies Inc..
//
////////////////////////////////////////////////////////////////////////////
package com.crankuptheamps.client;
import java.util.ArrayList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* MessageRouter is used to register and manage a list of handler objects for messages,
* as well as routing messages to those handlers as messages arrive.
* MessageRouter also "knows" about the meaning of AMPS acks and can use them to automatically
* clean up routes as acks arrive.
*/
public class MessageRouter
{
/**
* Adds a route to self.
*
* @param commandId_ The command, query, or subid used for this route.
* @param messageHandler_ The message handler to route to.
* @param requestedAcks_ The acks requested by the AMPS client infrastructure.
* @param systemAcks_ The acks requested by AMPS client infrastructure. These will not
* be delivered to the message handler, but are still processed for
* auto-removal.
* @param isSubscribe_ True if this route is for an ongoing subscription.
*/
public void addRoute(CommandId commandId_, MessageHandler messageHandler_, int requestedAcks_, int systemAcks_, boolean isSubscribe_)
{
_routes.put(commandId_, new MessageRoute(messageHandler_, requestedAcks_, systemAcks_, isSubscribe_));
}
/**
* Remove a route from MessageRouter.
*
* @param commandId_ The route to remove.
* @return true if the route was removed.
*/
public boolean removeRoute(CommandId commandId_)
{
return _routes.remove(commandId_) != null;
}
/**
* Find and return a route.
*
* @param commandId_ The command id for this route.
* @return The MessageHandler registered for this route, or null if none is
* registered.
*/
public MessageHandler findRoute(CommandId commandId_)
{
MessageRoute route = _routes.get(commandId_);
if(route != null)
return route.getMessageHandler();
else
return null;
}
/**
* Return whether or not a command id has a route.
*
* @param commandId_ The command id for this route.
* @return If a route is registered for the command id.
*/
public boolean hasRoute(CommandId commandId_)
{
return _routes.containsKey(commandId_);
}
/**
* Removes all routes for subscriptions.
*/
public void unsubscribeAll()
{
ArrayList subs = new ArrayList(_routes.size());
for (Map.Entry entry : _routes.entrySet())
{
if (entry.getValue().isTerminationAck(0)) subs.add(entry.getKey());
}
for (CommandId subId : subs)
{
removeRoute(subId);
}
}
/**
* Removes all routes from self (MessageRouter).
*/
public void clear()
{
_routes.clear();
}
/**
* Deliver a message that is known already to be an Ack. Coordinates the
* removal of routes based on the ack received and the original message type.
* @param ackMessage_ The Message to deliver.
* @param ackType_ The ack type from that message.
* @return The number of message deliveries that occurred
* @throws Exception Any exception from user message handlers.
*/
public int deliverAck(Message ackMessage_, int ackType_) throws Exception
{
assert(ackMessage_.getCommand() == Message.Command.Ack);
assert(ackType_ != Message.AckType.None);
int messagesDelivered = 0;
if(ackMessage_.getCommandId(_key))
{
messagesDelivered += _deliverAck(ackMessage_, ackType_, _key);
}
if(ackMessage_.getQueryId(_key))
{
if(messagesDelivered==0)
{
messagesDelivered += _deliverAck(ackMessage_, ackType_, _key);
} else {
_processAckForRemoval(ackType_, _key);
}
}
if(ackMessage_.getSubId(_key))
{
if(messagesDelivered == 0)
{
messagesDelivered += _deliverAck(ackMessage_, ackType_, _key);
} else {
_processAckForRemoval(ackType_, _key);
}
}
return messagesDelivered;
}
/**
* Delivers a data message (not an Ack) to the registered route.
* Uses the commandID, subID, and queryID to find a route and
* deliver to the first one found. This method is optimized for speed
* and does not attempt to examine ack types for removal of routes.
*
* @param dataMessage_ The non-ack message to deliver.
* @return The number of deliveries performed.
* @throws Exception Any exception thrown by the user message handler.
*/
public int deliverData(Message dataMessage_) throws Exception
{
assert(dataMessage_.getCommand() != Message.Command.Ack);
int messagesDelivered = 0;
if(messagesDelivered==0 && dataMessage_.getQueryId(_key))
{
messagesDelivered += deliverData(dataMessage_, _key);
}
if(dataMessage_.getCommandId(_key))
{
messagesDelivered += deliverData(dataMessage_, _key);
}
if(messagesDelivered==0 && dataMessage_.getSubId(_key))
{
messagesDelivered += deliverData(dataMessage_, _key);
}
return messagesDelivered;
}
/**
* Delivers a data message using a specific command ID from the message.
* Optimized
* for speed and does not attempt to examine the message for auto-removal of
* routes
*
* @param dataMessage_ The message to deliver.
* @param commandId_ The command ID which will be used to lookup the delivery
* route
* @return The number of deliveries performed.
* @throws Exception Any exception returned thrown by the message handler.
*/
public int deliverData(Message dataMessage_, CommandId commandId_) throws Exception
{
assert(dataMessage_.getCommand() != Message.Command.Ack);
int messagesDelivered = 0;
MessageRoute route = _routes.get(commandId_);
if(route!=null)
{
messagesDelivered += route.deliverData(dataMessage_);
}
return messagesDelivered;
}
//////////////// INTERNAL METHODS AND CLASSES ///////////////////
/**
* MessageRoute is an internal class representing a route in the MessageRouter.
* It holds information about the associated message handler, acks, and
* termination acks.
*/
static private class MessageRoute
{
MessageHandler _messageHandler;
int _systemAcks, _requestedAcks, _terminationAck;
public MessageRoute(MessageHandler messageHandler_, int requestedAcks_,
int systemAcks_, boolean isSubscribe_)
{
_messageHandler = messageHandler_;
_systemAcks = systemAcks_;
_requestedAcks = requestedAcks_;
// For non-subscriptions we autoremove a handler when the termination ack comes in.
if(!isSubscribe_)
{
// compute the termination ack we're looking for
// make terminationAck the highest bit set in all acks
int bitCounter = requestedAcks_ | systemAcks_;
while(bitCounter > 0) { bitCounter>>=1; _terminationAck = _terminationAck>0?2*_terminationAck:1; }
}
}
/**
* Deliver an ack message to the associated message handler.
*
* @param message_ The ack message to deliver.
* @param ackType_ The ack type from that message.
* @return The number of ack deliveries that occurred.
* @throws Exception Any exception from user message handlers.
*/
public int deliverAck(Message message_, int ackType_) throws Exception
{
// If it was a not a requested ack, do not deliver.
if( (_requestedAcks & ackType_) == 0) return 0;
_messageHandler.invoke(message_);
return 1;
}
/**
* Check if the given acknowledgement type is a termination acknowledgment.
*
* @param ackType_ The ack type to compare.
* @return True if the termination ack matches the given ack type.
*/
public boolean isTerminationAck(int ackType_)
{
return ackType_ == _terminationAck;
}
/**
* Deliver a data message to the associated message handler.
*
* @param message_ The data message to deliver.
* @return The number of data deliveries performed.
* @throws Exception Any exception from user message handlers.
*/
public int deliverData(Message message_) throws Exception
{
_messageHandler.invoke(message_);
return 1;
}
/**
* Get the associated message handler.
*
* @return The associated message handler.
*/
public MessageHandler getMessageHandler()
{
return _messageHandler;
}
/**
* Delivers an acknowledgment message to the appropriate route.
*
* @param ackMessage_ The acknowledgment message.
* @param ackType_ The type of acknowledgment.
* @param name="commandId_ The command ID associated with the acknowledgment.
* @return The number of messages delivered.
*/
}
private int _deliverAck(Message ackMessage_, int ackType_, CommandId commandId_) throws Exception
{
int messagesDelivered = 0;
MessageRoute route = _routes.get(commandId_);
if(route!=null)
{
messagesDelivered += route.deliverAck(ackMessage_, ackType_);
if(route.isTerminationAck(ackType_))
{
_routes.remove(commandId_);
}
}
return messagesDelivered;
}
/**
* Internal method to process an acknowledgment (Ack) for removal of routes.
* Checks if the ack type matches the termination ack and removes the associated
* route.
*
* @param ackType_ The ack type to process.
* @param commandId_ The command ID associated with the route.
*/
private void _processAckForRemoval(int ackType_, CommandId commandId_)
{
MessageRoute route = _routes.get(commandId_);
if(route != null && route.isTerminationAck(ackType_))
{
_routes.remove(commandId_);
}
}
/////////// MEMBER VARIABLES FOR MessageRouter /////////////
// Storage for current routes.
ConcurrentHashMap _routes = new ConcurrentHashMap();
// Cached CommandId object used for retrieval of command Ids.
CommandId _key = new CommandId();
}