Hi,
I'm thinking of creating a request ID aware Client which would be able to register any number of "default" listeners (where reqI=0), and listeners with specific (non-zero) request IDs would only get the packets they are subscribed for.
I realize that QueueClient is the one for encapsulating the request ID handling, but it seems to assign only the first listener to reqI=0, but then it sends all reqI=0 packets to all the listeners.
What do you think?
Edit: I've come up with this class. Use it if you need and/or like it.
<?php
package net.sf.jinsim;
import java.io.IOException;
import java.util.ArrayList;
import net.sf.jinsim.request.InSimRequest;
import net.sf.jinsim.response.InSimListener;
import net.sf.jinsim.response.InSimResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This Client handles both request and default listeners.
*
* Request listeners
* A request packet can be associated with a request listener via the send(packet,listener) method.
* The request packet will be signed with a request ID.
* Incoming packets with the same request ID are directed to the associated listener.
* A maximum number of 255 listeners is possible to be associated at a time.
*
* Default listeners
* The send(packet) method can be used to send requests without associating listeners.
* Incoming packets with the default (0) request ID are directed to "default" listeners.
* The number of default listeners is not limited.
*
* @author szaboaz at freemail dot hu
*/
public class RequestClient extends Client {
private static Logger log = LoggerFactory.getLogger(RequestClient.class);
//for reqI = 0
private ArrayList<InSimListener> defaultListeners;
//for reqI != 0
private InSimListener[] requestListeners;
public RequestClient() {
defaultListeners = new ArrayList<InSimListener>();
// "0" is taken as "default" from the byte type's 256 different values,
// so 255 other values remain.
requestListeners = new InSimListener[255];
// request ID = (array index + 1)
}
public void addDefaultListener(InSimListener listener) {
defaultListeners.add(listener);
}
public void removeDefaultListener(InSimListener listener) {
defaultListeners.remove(listener);
}
public void addRequestListener(InSimListener listener) {
// search for the next empty space in the array
int arrayIndex = 0;
while (requestListeners[arrayIndex] != null) {
arrayIndex++;
}
if (arrayIndex > 254) {
throw new IndexOutOfBoundsException("Maximum number of listeners exceeded!");
}
requestListeners[arrayIndex] = listener;
if (log.isDebugEnabled()) {
log.debug("Added " + listener.getClass().getName() + " to requestListeners at index " + arrayIndex);
}
}
public void removeRequestListener(InSimListener listener) {
if (listener != null) {
for (int i = 0; i < 255; i++) {
if (listener.equals(requestListeners[i])) {
requestListeners[i] = null;
}
}
}
}
@Override
public void notifyListeners(InSimResponse packetData) {
int requestID = packetData.getRequestInfo();
log.debug("\nIncoming packet " + packetData.getClass().getName());
log.debug("RequestID: " + requestID);
if (requestID == 0) {
for (InSimListener listener : defaultListeners) {
if (listener != null) {
log.debug("Packet goes to default listener: " + listener.getClass().getName() + "\n");
listener.packetReceived(packetData);
} else {
log.debug("Listener is null!\n");
}
}
} else {
InSimListener listener = requestListeners[requestID - 1];
if (listener != null) {
log.debug("Packet goes to request listener: " + listener.getClass().getName() + "\n");
listener.packetReceived(packetData);
} else {
log.debug("Listener is null!\n");
}
}
}
@Override
public void send(InSimRequest packet) throws IOException {
log.debug("Sending out packet.");
super.send(packet);
}
public void send(InSimRequest packet, InSimListener listener) throws IOException {
//let's get the array index of that listener
if (listener == null) {
log.debug("Listener is null!");
return;
}
int arrayIndex = 0;
while (!listener.equals(requestListeners[arrayIndex])) {
arrayIndex++;
}
//at this point, arrayIndex is the index of our listener
//and since requestID = array index + 1:
byte requestID = (byte) (arrayIndex + 1);
log.debug("Sending out packet with requestListener " + listener.getClass().getName() + " Index: " + requestID);
packet.setRequestInfo(requestID);
super.send(packet);
}
}
?>
Edit: as my understanding grows, I see how my humble class above might not be adequate for general use. I'm pondering about other requests where request ID is prohibited from being zero, for example button requests.
Maybe I should fix the code above by sending all responses whose request ID is not zero, still don't have specific listeners assigned to them, so all those responses should still go to (all of the) default listeners.
Edit: I did just that, here's the current version:
<?php
package net.sf.jinsim;
import java.io.IOException;
import java.util.ArrayList;
import net.sf.jinsim.request.InSimRequest;
import net.sf.jinsim.response.InSimListener;
import net.sf.jinsim.response.InSimResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* This Client handles both request and default listeners.
*
* Request listeners
* A request packet can be associated with a request listener via the send(packet,listener) method.
* The request packet will be signed with a request ID.
* Incoming packets with the same request ID are directed to the associated listener.
* If there are no listeners associated to the incoming packet's request ID, the packet
* will be sent to all default listeners.
* A maximum number of 255 listeners is possible to be associated at a time.
*
* Default listeners
* The send(packet) method can be used to send requests without associating listeners.
* Incoming packets with the default (0) request ID are directed to "default" listeners.
* The number of default listeners is not limited.
*
*
* @author szaboaz at freemail dot hu
*/
public class RequestClient extends Client {
private static Logger log = LoggerFactory.getLogger(RequestClient.class);
//for reqI = 0
private ArrayList<InSimListener> defaultListeners;
//for reqI != 0
private InSimListener[] requestListeners;
public RequestClient() {
defaultListeners = new ArrayList<InSimListener>();
// "0" is taken as "default" from the byte type's 256 different values,
// so 255 other values remain.
requestListeners = new InSimListener[255];
// request ID = (array index + 1)
}
public void addDefaultListener(InSimListener listener) {
defaultListeners.add(listener);
}
public void removeDefaultListener(InSimListener listener) {
defaultListeners.remove(listener);
}
public void addRequestListener(InSimListener listener) {
// search for the next empty space in the array
int arrayIndex = 0;
while (requestListeners[arrayIndex] != null) {
arrayIndex++;
}
if (arrayIndex > 254) {
throw new IndexOutOfBoundsException("Maximum number of listeners exceeded!");
}
requestListeners[arrayIndex] = listener;
if (log.isDebugEnabled()) {
log.debug("Added " + listener.getClass().getName() + " to requestListeners at index " + arrayIndex);
}
}
public void removeRequestListener(InSimListener listener) {
if (listener != null) {
for (int i = 0; i < 255; i++) {
if (listener.equals(requestListeners[i])) {
requestListeners[i] = null;
}
}
}
}
@Override
public void notifyListeners(InSimResponse packetData) {
int requestID = packetData.getRequestInfo();
log.debug("\nIncoming packet " + packetData.getClass().getName());
log.debug("RequestID: " + requestID);
if (requestID == 0) {
for (InSimListener defaultListener : defaultListeners) {
if (defaultListener != null) {
log.debug("Packet goes to default listener: " + defaultListener.getClass().getName() + "\n");
defaultListener.packetReceived(packetData);
} else {
log.debug("Listener is null!\n");
}
}
} else {
InSimListener listener = requestListeners[requestID - 1];
if (listener != null) {
log.debug("Packet goes to request listener: " + listener.getClass().getName() + "\n");
listener.packetReceived(packetData);
} else {
log.debug("No request listener is associated with this Request ID!\n");
for (InSimListener defaultListener : defaultListeners) {
if (defaultListener != null) {
log.debug("Packet goes to default listener: " + defaultListener.getClass().getName() + "\n");
defaultListener.packetReceived(packetData);
} else {
log.debug("Listener is null!\n");
}
}
}
}
}
@Override
public void send(InSimRequest packet) throws IOException {
log.debug("Sending out packet.");
super.send(packet);
}
public void send(InSimRequest packet, InSimListener listener) throws IOException {
//let's get the array index of that listener
if (listener == null) {
log.debug("Listener is null!");
return;
}
int arrayIndex = 0;
while (!listener.equals(requestListeners[arrayIndex])) {
arrayIndex++;
}
//at this point, arrayIndex is the index of our listener
//and since requestID = array index + 1:
byte requestID = (byte) (arrayIndex + 1);
log.debug("Sending out packet with requestListener " + listener.getClass().getName() + " Index: " + requestID);
packet.setRequestInfo(requestID);
super.send(packet);
}
}
?>
I've just realized another possible shortcoming: what if I want to use the same request ID with two different listeners. Not possible at the moment.
Of course if an incoming packet comes with a request ID, the same listener can handle different things... Still...
Edit: Okay, here's a new version. Any number of listeners can be assigned to any of the request IDs. It's more elegant too, without that ugly array
For convenience, there're methods for adding and removing listeners to all the request IDs.
<?php
package net.sf.jinsim;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import net.sf.jinsim.request.InSimRequest;
import net.sf.jinsim.response.InSimListener;
import net.sf.jinsim.response.InSimResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/*
* You can subscribe to this Client any number of
* - request ID specific listeners (which listen only to responses
* with the specified IDs).
* - general listeners (which listen to responses with any request IDs),
*
* Specified request ID values must be in the range of 0 to 255.
*
* @author szaboaz at freemail dot hu
*/
public class RequestClient extends Client {
private static Logger log = LoggerFactory.getLogger(RequestClient.class);
private ArrayList<HashSet<InSimListener>> listeners;
public RequestClient(){
listeners = new ArrayList<HashSet<InSimListener>>();
for (int i=0; i<=255; i++){
listeners.add(new HashSet<InSimListener>());
}
}
public boolean addListener(InSimListener listener) {
boolean returnValue = true;
for (int i=0; i<=255; i++){
returnValue = listeners.get(i).add(listener);
}
return returnValue;
}
public boolean addListener(InSimListener listener, int requestID) {
if (requestID >= 0 && requestID <=255){
return listeners.get(requestID).add(listener);
}
else {
return false;
}
}
public boolean removeListener(InSimListener listener) {
boolean returnValue = true;
for (int i=0; i<=255; i++){
returnValue = listeners.get(i).remove(listener);
}
return returnValue;
}
public boolean removeListener(InSimListener listener, int requestID) {
if (requestID >= 0 && requestID <=255){
return listeners.get(requestID).remove(listener);
}
else {
return false;
}
}
@Override
public void notifyListeners(InSimResponse packetData) {
int requestID = packetData.getRequestInfo();
HashSet<InSimListener> listenerSet = listeners.get(requestID);
for (InSimListener listener : listenerSet){
listener.packetReceived(packetData);
}
}
public void send(InSimRequest packet, int requestID) throws IOException {
packet.setRequestInfo((byte)requestID);
send(packet);
}
}
?>