diff --git a/src/net/sharksystem/asap/ASAPChunkFS.java b/src/net/sharksystem/asap/ASAPChunkFS.java index 86324bd..12af819 100644 --- a/src/net/sharksystem/asap/ASAPChunkFS.java +++ b/src/net/sharksystem/asap/ASAPChunkFS.java @@ -1,7 +1,6 @@ package net.sharksystem.asap; import net.sharksystem.asap.util.Helper; -import net.sharksystem.asap.util.Log; import java.io.*; import java.util.*; @@ -421,29 +420,4 @@ public int getEra() throws IOException { return this.era; } - private class MessageIter implements Iterator { - private final List byteMessages; - private int nextIndex; - private String nextString; - - - MessageIter(List byteMessages) throws FileNotFoundException { - this.byteMessages = byteMessages; - this.nextIndex = 0; - } - - @Override - public boolean hasNext() { - return this.byteMessages.size() > nextIndex; - } - - @Override - public String next() { - if(!this.hasNext()) { - throw new NoSuchElementException("no more messages"); - } - - return new String(this.byteMessages.get(nextIndex++)); - } - } } diff --git a/src/net/sharksystem/asap/MessageIter.java b/src/net/sharksystem/asap/MessageIter.java new file mode 100644 index 0000000..a55090e --- /dev/null +++ b/src/net/sharksystem/asap/MessageIter.java @@ -0,0 +1,32 @@ +package net.sharksystem.asap; + +import java.io.FileNotFoundException; +import java.util.Iterator; +import java.util.List; +import java.util.NoSuchElementException; + +public class MessageIter implements Iterator { + private final List byteMessages; + private int nextIndex; + private String nextString; + + + public MessageIter(List byteMessages) throws FileNotFoundException { + this.byteMessages = byteMessages; + this.nextIndex = 0; + } + + @Override + public boolean hasNext() { + return this.byteMessages.size() > nextIndex; + } + + @Override + public String next() { + if (!this.hasNext()) { + throw new NoSuchElementException("no more messages"); + } + + return new String(this.byteMessages.get(nextIndex++)); + } +} diff --git a/src/net/sharksystem/asap/apps/ASAPMessageReceivedListener.java b/src/net/sharksystem/asap/apps/ASAPMessageReceivedListener.java index 3dd5ef5..56d9607 100644 --- a/src/net/sharksystem/asap/apps/ASAPMessageReceivedListener.java +++ b/src/net/sharksystem/asap/apps/ASAPMessageReceivedListener.java @@ -2,6 +2,8 @@ import net.sharksystem.asap.ASAPMessages; +import java.io.IOException; + public interface ASAPMessageReceivedListener { - void asapMessagesReceived(ASAPMessages messages); + void asapMessagesReceived(ASAPMessages messages) throws IOException; } \ No newline at end of file diff --git a/src/net/sharksystem/asap/apps/ASAPMessageSender.java b/src/net/sharksystem/asap/apps/ASAPMessageSender.java new file mode 100644 index 0000000..d516ee2 --- /dev/null +++ b/src/net/sharksystem/asap/apps/ASAPMessageSender.java @@ -0,0 +1,15 @@ +package net.sharksystem.asap.apps; + +import net.sharksystem.asap.ASAPException; + +public interface ASAPMessageSender { + /** + * Send a message + * @param appName + * @param uri + * @param message + * @throws ASAPException + */ + void sendASAPMessage(CharSequence appName, CharSequence uri, + byte[] message) throws ASAPException; +} diff --git a/src/net/sharksystem/asap/apps/mock/ASAPMessagesMock.java b/src/net/sharksystem/asap/apps/mock/ASAPMessagesMock.java new file mode 100644 index 0000000..91dc205 --- /dev/null +++ b/src/net/sharksystem/asap/apps/mock/ASAPMessagesMock.java @@ -0,0 +1,56 @@ +package net.sharksystem.asap.apps.mock; + +import net.sharksystem.asap.ASAPException; +import net.sharksystem.asap.ASAPMessages; +import net.sharksystem.asap.MessageIter; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +class ASAPMessagesMock implements ASAPMessages { + private final CharSequence appName; + private final CharSequence uri; + private final List serializedAppPDUs; + + ASAPMessagesMock(CharSequence appName, CharSequence uri, List serializedAppPDUs) { + this.appName = appName; + this.uri = uri; + this.serializedAppPDUs = serializedAppPDUs; + } + + @Override + public int size() throws IOException { + return this.serializedAppPDUs.size(); + } + + @Override + public CharSequence getURI() { + return this.uri; + } + + @Override + public CharSequence getFormat() { + return this.appName; + } + + @Override + public Iterator getMessagesAsCharSequence() throws IOException { + return new MessageIter(this.serializedAppPDUs); + } + + @Override + public Iterator getMessages() throws IOException { + return this.serializedAppPDUs.iterator(); + } + + @Override + public CharSequence getMessageAsCharSequence(int position, boolean chronologically) throws ASAPException, IOException { + throw new ASAPException("not implemented in mocking class"); + } + + @Override + public byte[] getMessage(int position, boolean chronologically) throws ASAPException, IOException { + throw new ASAPException("not implemented in mocking class"); + } +} diff --git a/src/net/sharksystem/asap/apps/mock/ASAPSessionMock.java b/src/net/sharksystem/asap/apps/mock/ASAPSessionMock.java new file mode 100644 index 0000000..48d4553 --- /dev/null +++ b/src/net/sharksystem/asap/apps/mock/ASAPSessionMock.java @@ -0,0 +1,108 @@ +package net.sharksystem.asap.apps.mock; + +import net.sharksystem.asap.ASAPException; +import net.sharksystem.asap.ASAPMessages; +import net.sharksystem.asap.apps.ASAPMessageReceivedListener; +import net.sharksystem.asap.apps.ASAPMessageSender; + +import java.io.IOException; +import java.util.*; + +public class ASAPSessionMock implements ASAPMessageSender { + private Map>> appMsgStorage = new HashMap<>(); + private Map> listenerMap = new HashMap<>(); + private boolean connected = false; + + private List getStorage(CharSequence appName, CharSequence uri) { + Map> charSequenceListMap = this.appMsgStorage.get(appName); + if (charSequenceListMap == null) { + charSequenceListMap = new HashMap<>(); + this.appMsgStorage.put(appName, charSequenceListMap); + } + + List byteMessageList = charSequenceListMap.get(uri); + if (byteMessageList == null) { + byteMessageList = new ArrayList<>(); + charSequenceListMap.put(uri, byteMessageList); + } + + return byteMessageList; + } + + @Override + public void sendASAPMessage(CharSequence appName, CharSequence uri, byte[] message) throws ASAPException { + synchronized(this.appMsgStorage) { + List storage = this.getStorage(appName, uri); + storage.add(message); + } + + if(this.connected) this.notifyListeners(); + } + + public void addASAPMessageReceivedListener(CharSequence format, ASAPMessageReceivedListener listener) { + List asapMessageReceivedListeners = this.listenerMap.get(format); + if(asapMessageReceivedListeners == null) { + asapMessageReceivedListeners = new ArrayList<>(); + this.listenerMap.put(format, asapMessageReceivedListeners); + } + + asapMessageReceivedListeners.add(listener); + } + + /** + * Simulate a connection - this mock will notify all registered listeners and remove messages. + * After connected - any sendASAPMessage call will immediately lead to a listener call. + */ + public void connect() { + this.connected = true; + this.notifyListeners(); + } + + private void notifyListeners() { + Map>> appUriMessages = null; + synchronized(this.appMsgStorage) { + if(this.appMsgStorage.isEmpty()) return; + + // else copy + appUriMessages = this.appMsgStorage; + + // create empty + this.appMsgStorage = new HashMap<>(); + } + + // send + for(CharSequence appName : appUriMessages.keySet()) { + Map> appMap = appUriMessages.get(appName); + if(appMap != null) { + List asapMessageReceivedListeners = this.listenerMap.get(appName); + if(asapMessageReceivedListeners != null && !asapMessageReceivedListeners.isEmpty()) { + Set uris = appMap.keySet(); + for(CharSequence uri : uris) { + List serializedAppPDUs = appMap.get(uri); + for(ASAPMessageReceivedListener listener : asapMessageReceivedListeners) { + // create a thread for each listener + new Thread(new Runnable() { + @Override + public void run() { + ASAPMessages messagesMock = new ASAPMessagesMock(appName, uri, serializedAppPDUs); + try { + listener.asapMessagesReceived(messagesMock); + } catch (IOException e) { + e.printStackTrace(); + } + } + }).start(); + } + } + } + } + } + } + + /** + * disconnect - opposite of connect + */ + public void disconnect() { + this.connected = false; + } +} diff --git a/test/net/sharksystem/asap/mock/ASAPMockUsage.java b/test/net/sharksystem/asap/mock/ASAPMockUsage.java new file mode 100644 index 0000000..55e417b --- /dev/null +++ b/test/net/sharksystem/asap/mock/ASAPMockUsage.java @@ -0,0 +1,118 @@ +package net.sharksystem.asap.mock; + +import net.sharksystem.asap.ASAPException; +import net.sharksystem.asap.ASAPMessages; +import net.sharksystem.asap.apps.ASAPMessageSender; +import net.sharksystem.asap.apps.ASAPMessageReceivedListener; +import net.sharksystem.asap.apps.mock.ASAPSessionMock; +import org.junit.Test; + +import java.io.*; +import java.util.Iterator; + +/** + * How to mock ASAP communication + */ +public class ASAPMockUsage { + + private static final CharSequence YOUR_APP_NAME = "yourAppName"; + private static final CharSequence YOUR_URI = "yourSchema://example"; + + /** + * a serialization example + * @param exampleLong + * @param exampleString + * @param exampleBoolean + * @return + */ + private static byte[] serializeExample(long exampleLong, String exampleString, boolean exampleBoolean) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream daos = new DataOutputStream(baos); + + // serialize + daos.writeLong(exampleLong); + daos.writeUTF(exampleString); + daos.writeBoolean(exampleBoolean); + + return baos.toByteArray(); + } + + /** + * a deserialization example + */ + private static void deserializeExample(byte[] serializedData) throws IOException { + ByteArrayInputStream bais = new ByteArrayInputStream(serializedData); + DataInputStream dais = new DataInputStream(bais); + + // deserialize + long exampleLong = dais.readLong(); + String exampleString = dais.readUTF(); + boolean exampleBoolean = dais.readBoolean(); + + // call a methode in your app + + // here: just print + System.out.println("received: " + exampleLong + " | " + exampleString + " | " + exampleBoolean); + } + + @Test + public void usageTest1() throws IOException, ASAPException, InterruptedException { + /* Imagine we are here inside your application code. Data are to be transmitted. You implemented + a methode that serializes your data (PDU) into an array of bytes + */ + + // example - this should be produced by your application + byte[] serializedData = ASAPMockUsage.serializeExample(42, "don't panic", true); + + // now: ASAP is used to deliver those data - we mock it + ASAPSessionMock asapSessionMock = new ASAPSessionMock(); + + ASAPMessageSender asapMessageSender = asapSessionMock; + + asapMessageSender.sendASAPMessage(YOUR_APP_NAME, YOUR_URI, serializedData); + + // we simulated a sender - now, we need to simulate recipient + + // this should be replaced with your code - you must implement a listener. + ASAPMessageReceivedListenerExample asapMessageReceivedListenerExample = + new ASAPMessageReceivedListenerExample(); + + // register your listener (or that mock) with asap connection mock + asapSessionMock.addASAPMessageReceivedListener(YOUR_APP_NAME, asapMessageReceivedListenerExample); + + // simulate ASAP encounter + asapSessionMock.connect(); + + // give your app a moment to process + Thread.sleep(1000); + + // add another message while still connected + asapMessageSender.sendASAPMessage(YOUR_APP_NAME, YOUR_URI, + ASAPMockUsage.serializeExample(43, "second message", false)); + + asapSessionMock.disconnect(); + System.out.println("send message without connection"); + asapMessageSender.sendASAPMessage(YOUR_APP_NAME, YOUR_URI, + ASAPMockUsage.serializeExample(44, "third message", false)); + asapMessageSender.sendASAPMessage(YOUR_APP_NAME, YOUR_URI, + ASAPMockUsage.serializeExample(45, "forth message", false)); + Thread.sleep(1000); + + System.out.println("re-connect"); + asapSessionMock.connect(); + Thread.sleep(1000); + } + + private class ASAPMessageReceivedListenerExample implements ASAPMessageReceivedListener { + @Override + public void asapMessagesReceived(ASAPMessages messages) throws IOException { + CharSequence format = messages.getFormat(); + CharSequence uri = messages.getURI(); + System.out.println("asap message received (" + format + " | " + uri + "). size == " + messages.size()); + Iterator yourPDUIter = messages.getMessages(); + while (yourPDUIter.hasNext()) { + ASAPMockUsage.deserializeExample(yourPDUIter.next()); + } + } + } +}