diff --git a/publisher-subscriber/README.md b/publish-subscribe/README.md similarity index 94% rename from publisher-subscriber/README.md rename to publish-subscribe/README.md index fe7a110fca89..5e4d5c9ffb41 100644 --- a/publisher-subscriber/README.md +++ b/publish-subscribe/README.md @@ -1,5 +1,5 @@ --- -title: Publish-Subscribe pattern +title: Publish-Subscribe category: Behavioral language: en tag: @@ -135,7 +135,7 @@ public class TLender { LOGGER.error("An error has occurred!", e); } - TLender tLender = new TLender(topicCFName, topicName); + TLender lender = new TLender(topicCFName, topicName); System.out.println ("TLender Application Started"); System.out.println ("Press enter to quit application"); @@ -151,11 +151,11 @@ public class TLender { //Exit if user pressed enter or line is blank if (line == null || line.trim().length() == 0) { System.out.println("Exiting..."); - tLender.exit(); + lender.exit(); } else { //publish the entered rate double newRate = Double.parseDouble(line); - tLender.publishRate(newRate); + lender.publishRate(newRate); } } } catch(IOException e) { @@ -186,15 +186,6 @@ Initial rate is 6.0 Waiting for new rates... Press enter to quit application -Running the class: - -The class must be run after the TLender class is running since TLender spins up the activeMQ broker. - -In order to see the messages being sent to multiple subscribers multiple instance of the TBorrower class need to be run. Either run multiple instances in an IDE or execute the following command in a command line from the root folder after generating the target folder: - - -mvn exec:java -Dexec.mainClass=com.iluwatar.publishersubscriber.TBorrower -Dexec.args="TopicCF RateTopic 6" - ```java public class TBorrower implements MessageListener { @@ -282,7 +273,7 @@ public class TBorrower implements MessageListener { System.exit(0); } - TBorrower tBorrower = new TBorrower(topicCF, topicName, rate); + TBorrower borrower = new TBorrower(topicCF, topicName, rate); try { // Run until enter is pressed @@ -291,7 +282,7 @@ public class TBorrower implements MessageListener { System.out.println ("TBorrower application started"); System.out.println ("Press enter to quit application"); reader.readLine(); - tBorrower.exit(); + borrower.exit(); } catch (IOException ioe) { ioe.printStackTrace(); } @@ -316,6 +307,7 @@ public class TBorrower implements MessageListener { ``` ## Class diagram +![alt text](./etc/publishsubscribe.urm.png "Publish Subscribe class diagram") ## Applicability diff --git a/publish-subscribe/USAGE.md b/publish-subscribe/USAGE.md new file mode 100644 index 000000000000..92f82e688b25 --- /dev/null +++ b/publish-subscribe/USAGE.md @@ -0,0 +1,8 @@ +Running the Borrower class: + +The class must be run after the TLender class is running since TLender spins up the activeMQ broker. + +In order to see the messages being sent to multiple subscribers multiple instance of the TBorrower class need to be run. Either run multiple instances in an IDE or execute the following command in a command line from the root folder after generating the target folder: + + +mvn exec:java -Dexec.mainClass=com.iluwatar.publishsubscribe.Borrower -Dexec.args="TopicCF RateTopic 6" \ No newline at end of file diff --git a/publisher-subscriber/pom.xml b/publish-subscribe/pom.xml similarity index 92% rename from publisher-subscriber/pom.xml rename to publish-subscribe/pom.xml index 42b58399d89b..8b4d2806cd90 100644 --- a/publisher-subscriber/pom.xml +++ b/publish-subscribe/pom.xml @@ -35,7 +35,7 @@ java-design-patterns 1.26.0-SNAPSHOT - publishersubscriber + publishsubscribe @@ -58,11 +58,6 @@ xbean-spring 4.24 - - log4j - log4j - 1.2.17 - org.apache.activemq.tooling activemq-junit diff --git a/publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TBorrower.java b/publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Borrower.java similarity index 79% rename from publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TBorrower.java rename to publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Borrower.java index 1d489bdd00e0..1198fc5eeef3 100644 --- a/publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TBorrower.java +++ b/publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Borrower.java @@ -1,4 +1,4 @@ -package com.iluwatar.publishersubscriber; +package com.iluwatar.publishsubscribe; import lombok.extern.slf4j.Slf4j; import javax.jms.BytesMessage; @@ -19,14 +19,16 @@ import java.io.InputStreamReader; @Slf4j -public class TBorrower implements MessageListener { +public class Borrower implements MessageListener { private TopicConnection tConnection; private TopicSession tSession; private Topic topic; private double currentRate; + private static final String ERROR = "An error has occured!"; + private double newRate; - public TBorrower(String topicCFName, String topicName, double initialRate) { + public Borrower(String topicCFName, String topicName, double initialRate) { currentRate = initialRate; @@ -50,44 +52,37 @@ public TBorrower(String topicCFName, String topicName, double initialRate) { tConnection.start(); System.out.println("Initial rate is " + currentRate + " \nWaiting for new rates..."); } catch(NamingException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } } //This method is called asynchronously by the activeMQ broker public void onMessage(Message message) { - try { BytesMessage bMessage = (BytesMessage) message; - double newRate = ((BytesMessage) bMessage).readDouble(); + double newRate = bMessage.readDouble(); + setNewRate(newRate); if (currentRate - newRate >= 1) System.out.println("New Rate is " + newRate + " - Consider refinancing"); else System.out.println("New Rate is " + newRate + " - Consider keeping current rate"); } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } System.out.println("Waiting for new rates..."); } - private void exit() { + public boolean close() { try { tConnection.close(); + return true; } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); + return false; } - System.exit(0); } public static void main(String[] args) { @@ -105,7 +100,7 @@ public static void main(String[] args) { System.exit(0); } - TBorrower tBorrower = new TBorrower(topicCF, topicName, rate); + Borrower borrower = new Borrower(topicCF, topicName, rate); try { // Run until enter is pressed @@ -114,9 +109,10 @@ public static void main(String[] args) { System.out.println ("TBorrower application started"); System.out.println ("Press enter to quit application"); reader.readLine(); - tBorrower.exit(); - } catch (IOException ioe) { - ioe.printStackTrace(); + borrower.close(); + System.exit(0); + } catch (IOException e) { + LOGGER.error(ERROR, e); } } @@ -135,4 +131,8 @@ public Topic getTopic() { public double getCurrentRate() { return currentRate; } + + public double getNewRate() { return newRate; } + + private void setNewRate(double newRate) { this.newRate = newRate; } } diff --git a/publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TLender.java b/publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Lender.java similarity index 67% rename from publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TLender.java rename to publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Lender.java index 3536d69fdffa..dd504e57f49a 100644 --- a/publisher-subscriber/src/main/java/com/iluwatar/publishersubscriber/TLender.java +++ b/publish-subscribe/src/main/java/com/iluwatar/publishsubscribe/Lender.java @@ -1,4 +1,4 @@ -package com.iluwatar.publishersubscriber; +package com.iluwatar.publishsubscribe; import lombok.extern.slf4j.Slf4j; import org.apache.activemq.broker.BrokerService; @@ -14,18 +14,23 @@ import javax.naming.InitialContext; import javax.naming.NamingException; import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; +import java.util.Properties; @Slf4j -public class TLender { +public class Lender { private TopicConnection tConnection; private TopicSession tSession; private Topic topic; private TopicPublisher publisher; + private static final String ERROR = "An error has occured!"; - public TLender(String topicCFName, String topicName) { + public Lender(String topicCFName, String topicName) { try { //create context and retrieve objects from directory @@ -44,17 +49,13 @@ public TLender(String topicCFName, String topicName) { tConnection.start(); } catch(NamingException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } } - private void publishRate(double newRate) { + public void publishRate(double newRate) { try { //create JMS message @@ -64,21 +65,18 @@ private void publishRate(double newRate) { //publish message publisher.publish(message); } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); } } - private void exit() { + public boolean close() { try { tConnection.close(); + return true; } catch(JMSException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); - System.exit(1); + LOGGER.error(ERROR, e); + return false; } - System.exit(0); } public static void main(String[] args) { @@ -90,26 +88,35 @@ public static void main(String[] args) { topicCFName = args[0]; topicName = args[1]; } else { - System.out.println("Invalid arguments. Should be: "); - System.out.println("java TLender [factory] [topic]"); + LOGGER.info("Invalid arguments. Should be: "); + LOGGER.info("java TLender [factory] [topic]"); System.exit(1); } try { + //Get configuration properties + Properties props = new Properties(); + InputStream in = new FileInputStream("publish-subscribe/src/main/resources/config.properties"); + props.load(in); + in.close(); + // Create and start activeMQ broker. Broker decouples publishers and subscribers. - //Additionally brokers manage threads and asynchronous sending and receiving of messages. + // Additionally brokers manage threads and asynchronous sending and receiving of messages. BrokerService broker = new BrokerService(); - broker.addConnector("tcp://localhost:61616"); + broker.addConnector(props.getProperty("ADDRESS")); broker.start(); + } catch(FileNotFoundException e) { + LOGGER.error(ERROR, e); + } catch(IOException e) { + LOGGER.error(ERROR, e); } catch(Exception e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); + LOGGER.error(ERROR, e); } - TLender tLender = new TLender(topicCFName, topicName); + Lender lender = new Lender(topicCFName, topicName); - System.out.println ("TLender Application Started"); + LOGGER.info("TLender Application Started"); System.out.println ("Press enter to quit application"); System.out.println ("Enter: Rate"); System.out.println("\ne.g. 6.8"); @@ -123,16 +130,16 @@ public static void main(String[] args) { //Exit if user pressed enter or line is blank if (line == null || line.trim().length() == 0) { System.out.println("Exiting..."); - tLender.exit(); + lender.close(); + System.exit(0); } else { //publish the entered rate double newRate = Double.parseDouble(line); - tLender.publishRate(newRate); + lender.publishRate(newRate); } } } catch(IOException e) { - e.printStackTrace(); - LOGGER.error("An error has occurred!", e); + LOGGER.error(ERROR, e); } } diff --git a/publish-subscribe/src/main/resources/config.properties b/publish-subscribe/src/main/resources/config.properties new file mode 100644 index 000000000000..c90ed24de061 --- /dev/null +++ b/publish-subscribe/src/main/resources/config.properties @@ -0,0 +1 @@ +ADDRESS=tcp://localhost:61616 \ No newline at end of file diff --git a/publisher-subscriber/src/main/resources/jndi.properties b/publish-subscribe/src/main/resources/jndi.properties similarity index 100% rename from publisher-subscriber/src/main/resources/jndi.properties rename to publish-subscribe/src/main/resources/jndi.properties diff --git a/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/BorrowerTest.java b/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/BorrowerTest.java new file mode 100644 index 000000000000..ded88e244087 --- /dev/null +++ b/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/BorrowerTest.java @@ -0,0 +1,78 @@ +package com.iluwatar.publishsubscribe; + +import org.apache.activemq.Message; +import org.apache.activemq.broker.Broker; +import org.apache.activemq.broker.BrokerService; +import org.apache.activemq.command.ActiveMQTextMessage; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import javax.jms.BytesMessage; +import javax.jms.JMSException; +import javax.jms.TextMessage; +import java.io.BufferedOutputStream; +import java.io.ByteArrayOutputStream; +import java.io.OutputStream; +import java.io.PrintStream; +import java.sql.SQLOutput; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class BorrowerTest { + + private Borrower borrower; + private static BrokerService broker; + + @BeforeAll + static void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.start(); + } + + @AfterAll + static void tearDown() throws Exception { + broker.stop(); + } + + @Test + void testTBorrowerConstructor() { + //act + borrower = new Borrower("TopicCF", "RateTopic", 6.0); //Arbitrary rate + + //assert + Assertions.assertNotNull(borrower.gettConnection()); + Assertions.assertNotNull(borrower.getTopic()); + Assertions.assertNotNull(borrower.gettSession()); + } + + @Test + void testOnMessage() throws JMSException { + //assemble + borrower = new Borrower("TopicCF", "RateTopic", 6.0); + BytesMessage msg = borrower.gettSession().createBytesMessage(); + msg.writeDouble(5); + msg.reset(); + + //act + borrower.onMessage(msg); + + //assert + Assertions.assertEquals(borrower.getNewRate(), 5); + } + + @Test + void testClose() { + //assemble + borrower = new Borrower("TopicCF", "RateTopic", 6.0); + + //act + boolean isClosed = borrower.close(); + + //assert + Assertions.assertTrue(isClosed); + } +} diff --git a/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/LenderTest.java b/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/LenderTest.java new file mode 100644 index 000000000000..a103b0d9850f --- /dev/null +++ b/publish-subscribe/src/test/java/com/iluwatar/publishsubscribe/LenderTest.java @@ -0,0 +1,50 @@ +package com.iluwatar.publishsubscribe; + +import org.apache.activemq.broker.BrokerService; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class LenderTest { + + private Lender lender; + private static BrokerService broker; + + @BeforeAll + static void setUp() throws Exception { + broker = new BrokerService(); + broker.setPersistent(false); + broker.start(); + } + + @AfterAll + static void tearDown() throws Exception { + broker.stop(); + } + + @Test + void testTLenderConstructor() { + //act + lender = new Lender("TopicCF", "RateTopic"); + + //assert + Assertions.assertNotNull(lender.gettConnection()); + Assertions.assertNotNull(lender.getTopic()); + Assertions.assertNotNull(lender.gettSession()); + } + + @Test + void textExit() { + //assemble + lender = new Lender("TopicCF", "RateTopic"); + + //act + boolean isClosed = lender.close(); + + //assert + Assertions.assertTrue(isClosed); + } +} diff --git a/publisher-subscriber/src/test/resources/jndi.properties b/publish-subscribe/src/test/resources/jndi.properties similarity index 100% rename from publisher-subscriber/src/test/resources/jndi.properties rename to publish-subscribe/src/test/resources/jndi.properties diff --git a/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TBorrowerTest.java b/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TBorrowerTest.java deleted file mode 100644 index b59e421d5b90..000000000000 --- a/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TBorrowerTest.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.iluwatar.publishersubscriber; - -import org.apache.activemq.broker.BrokerService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; - -public class TBorrowerTest { - - private TBorrower tBorrower; - - void setUp() throws Exception { - BrokerService broker = new BrokerService(); - broker.setPersistent(false); - broker.start(); - } - - @Test - void testTBorrowerConstructor() { - //act - tBorrower = new TBorrower("TopicCF", "RateTopic", 6.0); //Arbitrary rate - - //assert - Assertions.assertNotNull(tBorrower.gettConnection()); - Assertions.assertNotNull(tBorrower.getTopic()); - Assertions.assertNotNull(tBorrower.gettSession()); - } -} diff --git a/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TLenderTest.java b/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TLenderTest.java deleted file mode 100644 index 9ec82e02109f..000000000000 --- a/publisher-subscriber/src/test/java/com/iluwatar/publishersubscriber/TLenderTest.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.iluwatar.publishersubscriber; - -import org.apache.activemq.broker.BrokerService; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; -import javax.jms.Connection; -import javax.jms.JMSException; -import javax.jms.Session; -import javax.jms.Topic; -import javax.jms.TopicConnectionFactory; -import javax.jms.TopicPublisher; - -public class TLenderTest { - - private TLender tLender; - - void setUp() throws Exception { - BrokerService broker = new BrokerService(); - broker.setPersistent(false); - broker.start(); - } - - @Test - void testTLenderConstructor() { - //act - tLender = new TLender("TopicCF", "RateTopic"); - - //assert - Assertions.assertNotNull(tLender.gettConnection()); - Assertions.assertNotNull(tLender.getTopic()); - Assertions.assertNotNull(tLender.gettSession()); - } -}