From dc0f578f8b06c22ea33dfbf2be46e38036d2d006 Mon Sep 17 00:00:00 2001 From: vehpsr Date: Sun, 5 Apr 2015 18:03:16 +0300 Subject: [PATCH] added Poison Pill idiom --- README.md | 9 +- poison-pill/etc/poison-pill.png | Bin 0 -> 15833 bytes poison-pill/etc/poison-pill.ucls | 92 ++++++++++++++++++ poison-pill/pom.xml | 18 ++++ .../src/main/java/com/iluwatar/App.java | 37 +++++++ .../src/main/java/com/iluwatar/Consumer.java | 38 ++++++++ .../java/com/iluwatar/MQPublishPoint.java | 9 ++ .../java/com/iluwatar/MQSubscribePoint.java | 9 ++ .../src/main/java/com/iluwatar/Message.java | 52 ++++++++++ .../main/java/com/iluwatar/MessageQueue.java | 8 ++ .../src/main/java/com/iluwatar/Producer.java | 48 +++++++++ .../main/java/com/iluwatar/SimpleMessage.java | 39 ++++++++ .../java/com/iluwatar/SimpleMessageQueue.java | 27 +++++ .../src/test/java/com/iluwatar/AppTest.java | 12 +++ pom.xml | 1 + 15 files changed, 398 insertions(+), 1 deletion(-) create mode 100644 poison-pill/etc/poison-pill.png create mode 100644 poison-pill/etc/poison-pill.ucls create mode 100644 poison-pill/pom.xml create mode 100644 poison-pill/src/main/java/com/iluwatar/App.java create mode 100644 poison-pill/src/main/java/com/iluwatar/Consumer.java create mode 100644 poison-pill/src/main/java/com/iluwatar/MQPublishPoint.java create mode 100644 poison-pill/src/main/java/com/iluwatar/MQSubscribePoint.java create mode 100644 poison-pill/src/main/java/com/iluwatar/Message.java create mode 100644 poison-pill/src/main/java/com/iluwatar/MessageQueue.java create mode 100644 poison-pill/src/main/java/com/iluwatar/Producer.java create mode 100644 poison-pill/src/main/java/com/iluwatar/SimpleMessage.java create mode 100644 poison-pill/src/main/java/com/iluwatar/SimpleMessageQueue.java create mode 100644 poison-pill/src/test/java/com/iluwatar/AppTest.java diff --git a/README.md b/README.md index f584edc61..90d487b91 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ A programming idiom is a means of expressing a recurring construct in one or mor * [Execute Around](#execute-around) * [Double Checked Locking](#double-checked-locking) - +* [Poison Pill](#poison-pill) ## Abstract Factory [↑](#list-of-design-patterns) @@ -475,6 +475,13 @@ A programming idiom is a means of expressing a recurring construct in one or mor **Real world examples:** * [JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain) prototype inheritance +## Poison Pill [↑](#list-of-design-patterns) +**Intent:** Poison Pill is known predefined data item that allows to provide graceful shutdown for separate distributed consumption process. + +![alt text](https://github.com/iluwatar/java-design-patterns/blob/master/poison-pill/etc/poison-pill.png "Poison Pill") + +**Applicability:** Use the Poison Pill idiom when +* need to send signal from one thread/process to another to terminate # Frequently asked questions diff --git a/poison-pill/etc/poison-pill.png b/poison-pill/etc/poison-pill.png new file mode 100644 index 0000000000000000000000000000000000000000..bfca5848e082c8fc69e6e7f4d5aa38af13ab27dc GIT binary patch literal 15833 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 Szj%*bpdhCzTP*YR)&B>iXFe1F literal 0 HcmV?d00001 diff --git a/poison-pill/etc/poison-pill.ucls b/poison-pill/etc/poison-pill.ucls new file mode 100644 index 000000000..6d20b1974 --- /dev/null +++ b/poison-pill/etc/poison-pill.ucls @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/poison-pill/pom.xml b/poison-pill/pom.xml new file mode 100644 index 000000000..1d9d4c38a --- /dev/null +++ b/poison-pill/pom.xml @@ -0,0 +1,18 @@ + + + 4.0.0 + + com.iluwatar + java-design-patterns + 1.0-SNAPSHOT + + poison-pill + + + junit + junit + test + + + diff --git a/poison-pill/src/main/java/com/iluwatar/App.java b/poison-pill/src/main/java/com/iluwatar/App.java new file mode 100644 index 000000000..22de1dd28 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/App.java @@ -0,0 +1,37 @@ +package com.iluwatar; + +/** + * One of possible approaches to terminate Producer-Consumer pattern is using PoisonPill idiom. + * If you use PoisonPill as termination signal then Producer is responsible to notify Consumer that exchange is over + * and reject any further messages. Consumer receiving PoisonPill will stop to read messages from queue. + * You also must ensure that PoisonPill will be last message that will be read from queue (if you have + * prioritized queue than this can be tricky). + * In simple cases as PoisonPill can be used just null-reference, but holding unique separate shared + * object-marker (with name "Poison" or "PoisonPill") is more clear and self describing. + */ +public class App { + + public static void main(String[] args) { + MessageQueue queue = new SimpleMessageQueue(10000); + + final Producer producer = new Producer("PRODUCER_1", queue); + final Consumer consumer = new Consumer("CONSUMER_1", queue); + + new Thread() { + @Override + public void run() { + consumer.consume(); + } + }.start(); + + new Thread() { + @Override + public void run() { + producer.send("hand shake"); + producer.send("some very important information"); + producer.send("bye!"); + producer.stop(); + } + }.start(); + } +} diff --git a/poison-pill/src/main/java/com/iluwatar/Consumer.java b/poison-pill/src/main/java/com/iluwatar/Consumer.java new file mode 100644 index 000000000..499971b6c --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/Consumer.java @@ -0,0 +1,38 @@ +package com.iluwatar; + +import com.iluwatar.Message.Headers; + +/** + * Class responsible for receiving and handling submitted to the queue messages + */ +public class Consumer { + + private final MQSubscribePoint queue; + private final String name; + + public Consumer(String name, MQSubscribePoint queue) { + this.name = name; + this.queue = queue; + } + + public void consume() { + while (true) { + Message msg; + try { + msg = queue.take(); + if (msg == Message.POISON_PILL) { + System.out.println(String.format("Consumer %s receive request to terminate.", name)); + break; + } + } catch (InterruptedException e) { + // allow thread to exit + System.err.println(e); + return; + } + + String sender = msg.getHeader(Headers.SENDER); + String body = msg.getBody(); + System.out.println(String.format("Message [%s] from [%s] received by [%s]", body, sender, name)); + } + } +} diff --git a/poison-pill/src/main/java/com/iluwatar/MQPublishPoint.java b/poison-pill/src/main/java/com/iluwatar/MQPublishPoint.java new file mode 100644 index 000000000..6cc830e71 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/MQPublishPoint.java @@ -0,0 +1,9 @@ +package com.iluwatar; + +/** + * Endpoint to publish {@link Message} to queue + */ +public interface MQPublishPoint { + + public void put(Message msg) throws InterruptedException; +} diff --git a/poison-pill/src/main/java/com/iluwatar/MQSubscribePoint.java b/poison-pill/src/main/java/com/iluwatar/MQSubscribePoint.java new file mode 100644 index 000000000..5e15ba7b9 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/MQSubscribePoint.java @@ -0,0 +1,9 @@ +package com.iluwatar; + +/** + * Endpoint to retrieve {@link Message} from queue + */ +public interface MQSubscribePoint { + + public Message take() throws InterruptedException; +} diff --git a/poison-pill/src/main/java/com/iluwatar/Message.java b/poison-pill/src/main/java/com/iluwatar/Message.java new file mode 100644 index 000000000..e9a67fe59 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/Message.java @@ -0,0 +1,52 @@ +package com.iluwatar; + +import java.util.Map; + +/** + * Interface that implements the Message pattern and represents an inbound or outbound message as part of an {@link Producer}-{@link Consumer} exchange. + */ +public interface Message { + + public static final Message POISON_PILL = new Message() { + + @Override + public void addHeader(Headers header, String value) { + throw poison(); + } + + @Override + public String getHeader(Headers header) { + throw poison(); + } + + @Override + public Map getHeaders() { + throw poison(); + } + + @Override + public void setBody(String body) { + throw poison(); + } + + @Override + public String getBody() { + throw poison(); + } + + private RuntimeException poison() { + return new UnsupportedOperationException("Poison"); + } + + }; + + public enum Headers { + DATE, SENDER + } + + public void addHeader(Headers header, String value); + public String getHeader(Headers header); + public Map getHeaders(); + public void setBody(String body); + public String getBody(); +} diff --git a/poison-pill/src/main/java/com/iluwatar/MessageQueue.java b/poison-pill/src/main/java/com/iluwatar/MessageQueue.java new file mode 100644 index 000000000..03ced489b --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/MessageQueue.java @@ -0,0 +1,8 @@ +package com.iluwatar; + +/** + * Represents abstraction of channel (or pipe) that bounds {@link Producer} and {@link Consumer} + */ +public interface MessageQueue extends MQPublishPoint, MQSubscribePoint { + +} diff --git a/poison-pill/src/main/java/com/iluwatar/Producer.java b/poison-pill/src/main/java/com/iluwatar/Producer.java new file mode 100644 index 000000000..89fb75277 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/Producer.java @@ -0,0 +1,48 @@ +package com.iluwatar; + +import java.util.Date; + +import com.iluwatar.Message.Headers; + +/** + * Class responsible for producing unit of work that can be expressed as message and submitted to queue + */ +public class Producer { + + private final MQPublishPoint queue; + private final String name; + private boolean isStopped; + + public Producer(String name, MQPublishPoint queue) { + this.name = name; + this.queue = queue; + this.isStopped = false; + } + + public void send(String body) { + if (isStopped) { + throw new IllegalStateException(String.format("Producer %s was stopped and fail to deliver requested message [%s].", body, name)); + } + Message msg = new SimpleMessage(); + msg.addHeader(Headers.DATE, new Date().toString()); + msg.addHeader(Headers.SENDER, name); + msg.setBody(body); + + try { + queue.put(msg); + } catch (InterruptedException e) { + // allow thread to exit + System.err.println(e); + } + } + + public void stop() { + isStopped = true; + try { + queue.put(Message.POISON_PILL); + } catch (InterruptedException e) { + // allow thread to exit + System.err.println(e); + } + } +} diff --git a/poison-pill/src/main/java/com/iluwatar/SimpleMessage.java b/poison-pill/src/main/java/com/iluwatar/SimpleMessage.java new file mode 100644 index 000000000..27b8db08b --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/SimpleMessage.java @@ -0,0 +1,39 @@ +package com.iluwatar; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * {@link Message} basic implementation + */ +public class SimpleMessage implements Message { + + private Map headers = new HashMap<>(); + private String body; + + @Override + public void addHeader(Headers header, String value) { + headers.put(header, value); + } + + @Override + public String getHeader(Headers header) { + return headers.get(header); + } + + @Override + public Map getHeaders() { + return Collections.unmodifiableMap(headers); + } + + @Override + public void setBody(String body) { + this.body = body; + } + + @Override + public String getBody() { + return body; + } +} diff --git a/poison-pill/src/main/java/com/iluwatar/SimpleMessageQueue.java b/poison-pill/src/main/java/com/iluwatar/SimpleMessageQueue.java new file mode 100644 index 000000000..12d519ce2 --- /dev/null +++ b/poison-pill/src/main/java/com/iluwatar/SimpleMessageQueue.java @@ -0,0 +1,27 @@ +package com.iluwatar; + +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * Bounded blocking queue wrapper + */ +public class SimpleMessageQueue implements MessageQueue { + + private final BlockingQueue queue; + + public SimpleMessageQueue(int bound) { + queue = new ArrayBlockingQueue(bound); + } + + @Override + public void put(Message msg) throws InterruptedException { + queue.put(msg); + } + + @Override + public Message take() throws InterruptedException { + return queue.take(); + } + +} diff --git a/poison-pill/src/test/java/com/iluwatar/AppTest.java b/poison-pill/src/test/java/com/iluwatar/AppTest.java new file mode 100644 index 000000000..6db5ad214 --- /dev/null +++ b/poison-pill/src/test/java/com/iluwatar/AppTest.java @@ -0,0 +1,12 @@ +package com.iluwatar; + +import org.junit.Test; + +public class AppTest { + + @Test + public void test() { + String[] args = {}; + App.main(args); + } +} diff --git a/pom.xml b/pom.xml index d81be42c9..d05182607 100644 --- a/pom.xml +++ b/pom.xml @@ -44,6 +44,7 @@ execute-around property intercepting-filter + poison-pill