Skip to content

Commit 82b9f4f

Browse files
authored
Merge pull request iluwatar#544 from kemitix/data-bus
[WIP] Data Bus
2 parents 31f4b15 + ff8d854 commit 82b9f4f

19 files changed

+894
-0
lines changed

data-bus/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

data-bus/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
---
2+
layout: pattern
3+
title: Data Bus
4+
folder: data-bus
5+
permalink: /patterns/data-bus/
6+
7+
categories: Architectural
8+
tags:
9+
- Java
10+
- Difficulty-Intermediate
11+
---
12+
13+
## Intent
14+
15+
Allows send of messages/events between components of an application
16+
without them needing to know about each other. They only need to know
17+
about the type of the message/event being sent.
18+
19+
![data bus pattern uml diagram](./etc/data-bus.urm.png "Data Bus pattern")
20+
21+
## Applicability
22+
Use Data Bus pattern when
23+
24+
* you want your components to decide themselves which messages/events they want to receive
25+
* you want to have many-to-many communication
26+
* you want your components to know nothing about each other
27+
28+
## Related Patterns
29+
Data Bus is similar to
30+
31+
* Mediator pattern with Data Bus Members deciding for themselves if they want to accept any given message
32+
* Observer pattern but supporting many-to-many communication
33+
* Publish/Subscribe pattern with the Data Bus decoupling the publisher and the subscriber

data-bus/etc/data-bus.urm.png

59.7 KB
Loading

data-bus/etc/data-bus.urm.puml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
@startuml
2+
package com.iluwatar.databus {
3+
class AbstractDataType {
4+
- dataBus : DataBus
5+
+ AbstractDataType()
6+
+ getDataBus() : DataBus
7+
+ setDataBus(dataBus : DataBus)
8+
}
9+
~class App {
10+
- log : Logger {static}
11+
~ App()
12+
+ main(args : String[]) {static}
13+
}
14+
class DataBus {
15+
- INSTANCE : DataBus {static}
16+
- listeners : Set<Member>
17+
+ DataBus()
18+
+ getInstance() : DataBus {static}
19+
+ publish(event : DataType)
20+
+ subscribe(member : Member)
21+
+ unsubscribe(member : Member)
22+
}
23+
interface DataType {
24+
+ getDataBus() : DataBus {abstract}
25+
+ setDataBus(DataBus) {abstract}
26+
}
27+
interface Member {
28+
+ accept(DataType) {abstract}
29+
}
30+
}
31+
package com.iluwatar.databus.data {
32+
class MessageData {
33+
- message : String
34+
+ MessageData(message : String)
35+
+ getMessage() : String
36+
+ of(message : String) : DataType {static}
37+
}
38+
class StartingData {
39+
- when : LocalDateTime
40+
+ StartingData(when : LocalDateTime)
41+
+ getWhen() : LocalDateTime
42+
+ of(when : LocalDateTime) : DataType {static}
43+
}
44+
class StoppingData {
45+
- when : LocalDateTime
46+
+ StoppingData(when : LocalDateTime)
47+
+ getWhen() : LocalDateTime
48+
+ of(when : LocalDateTime) : DataType {static}
49+
}
50+
}
51+
package com.iluwatar.databus.members {
52+
class CounterMember {
53+
- log : Logger {static}
54+
- name : String
55+
+ CounterMember(name : String)
56+
+ accept(data : DataType)
57+
- handleEvent(data : MessageData)
58+
}
59+
class StatusMember {
60+
- id : int
61+
- log : Logger {static}
62+
+ StatusMember(id : int)
63+
+ accept(data : DataType)
64+
- handleEvent(data : StartingData)
65+
- handleEvent(data : StoppingData)
66+
}
67+
}
68+
AbstractDataType --> "-dataBus" DataBus
69+
DataBus --> "-INSTANCE" DataBus
70+
DataBus --> "-listeners" Member
71+
AbstractDataType ..|> DataType
72+
MessageData --|> AbstractDataType
73+
StartingData --|> AbstractDataType
74+
StoppingData --|> AbstractDataType
75+
CounterMember ..|> Member
76+
StatusMember ..|> Member
77+
@enduml

data-bus/pom.xml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?xml version="1.0"?>
2+
<!--
3+
4+
The MIT License
5+
Copyright (c) 2014-2016 Ilkka Seppälä
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
25+
-->
26+
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
27+
xmlns="http://maven.apache.org/POM/4.0.0"
28+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
29+
<modelVersion>4.0.0</modelVersion>
30+
<properties>
31+
<lombok.version>1.16.14</lombok.version>
32+
</properties>
33+
<parent>
34+
<groupId>com.iluwatar</groupId>
35+
<artifactId>java-design-patterns</artifactId>
36+
<version>1.16.0-SNAPSHOT</version>
37+
</parent>
38+
<artifactId>data-bus</artifactId>
39+
<dependencies>
40+
<dependency>
41+
<groupId>junit</groupId>
42+
<artifactId>junit</artifactId>
43+
<scope>test</scope>
44+
</dependency>
45+
<dependency>
46+
<groupId>org.mockito</groupId>
47+
<artifactId>mockito-core</artifactId>
48+
<scope>test</scope>
49+
</dependency>
50+
</dependencies>
51+
</project>
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
The MIT License (MIT)
3+
4+
Copyright (c) 2016 Paul Campbell
5+
6+
Permission is hereby granted, free of charge, to any person obtaining a copy
7+
of this software and associated documentation files (the "Software"), to deal
8+
in the Software without restriction, including without limitation the rights
9+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
copies of the Software, and to permit persons to whom the Software is
11+
furnished to do so, subject to the following conditions:
12+
13+
The above copyright notice and this permission notice shall be included in all
14+
copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
SOFTWARE.
23+
*/
24+
25+
package com.iluwatar.databus;
26+
27+
/**
28+
* Base for data to send via the Data-Bus.
29+
*
30+
* @author Paul Campbell (pcampbell@kemitix.net)
31+
*/
32+
public class AbstractDataType implements DataType {
33+
34+
private DataBus dataBus;
35+
36+
@Override
37+
public DataBus getDataBus() {
38+
return dataBus;
39+
}
40+
41+
@Override
42+
public void setDataBus(DataBus dataBus) {
43+
this.dataBus = dataBus;
44+
}
45+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014-2016 Ilkka Seppälä
4+
* <p>
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
* <p>
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
* <p>
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.databus;
25+
26+
import com.iluwatar.databus.data.MessageData;
27+
import com.iluwatar.databus.data.StartingData;
28+
import com.iluwatar.databus.data.StoppingData;
29+
import com.iluwatar.databus.members.MessageCollectorMember;
30+
import com.iluwatar.databus.members.StatusMember;
31+
32+
import java.time.LocalDateTime;
33+
34+
/**
35+
* The Data Bus pattern
36+
* <p>
37+
* <p>{@see http://wiki.c2.com/?DataBusPattern}</p>
38+
* <p>
39+
* <p>The Data-Bus pattern provides a method where different parts of an application may
40+
* pass messages between each other without needing to be aware of the other's existence.</p>
41+
* <p>Similar to the {@code ObserverPattern}, members register themselves with the {@link DataBus}
42+
* and may then receive each piece of data that is published to the Data-Bus. The member
43+
* may react to any given message or not.</p>
44+
* <p>It allows for Many-to-Many distribution of data, as there may be any number of
45+
* publishers to a Data-Bus, and any number of members receiving the data. All members
46+
* will receive the same data, the order each receives a given piece of data, is an
47+
* implementation detail.</p>
48+
* <p>Members may unsubscribe from the Data-Bus to stop receiving data.</p>
49+
* <p>This example of the pattern implements a Synchronous Data-Bus, meaning that
50+
* when data is published to the Data-Bus, the publish method will not return until
51+
* all members have received the data and returned.</p>
52+
* <p>The {@link DataBus} class is a Singleton.</p>
53+
* <p>Members of the Data-Bus must implement the {@link Member} interface.</p>
54+
* <p>Data to be published via the Data-Bus must implement the {@link DataType} interface.</p>
55+
* <p>The {@code data} package contains example {@link DataType} implementations.</p>
56+
* <p>The {@code members} package contains example {@link Member} implementations.</p>
57+
* <p>The {@link StatusMember} demonstrates using the DataBus to publish a message
58+
* to the Data-Bus when it receives a message.</p>
59+
*
60+
* @author Paul Campbell (pcampbell@kemitix.net)
61+
*/
62+
class App {
63+
64+
public static void main(String[] args) {
65+
final DataBus bus = DataBus.getInstance();
66+
bus.subscribe(new StatusMember(1));
67+
bus.subscribe(new StatusMember(2));
68+
final MessageCollectorMember foo = new MessageCollectorMember("Foo");
69+
final MessageCollectorMember bar = new MessageCollectorMember("Bar");
70+
bus.subscribe(foo);
71+
bus.publish(StartingData.of(LocalDateTime.now()));
72+
bus.publish(MessageData.of("Only Foo should see this"));
73+
bus.subscribe(bar);
74+
bus.publish(MessageData.of("Foo and Bar should see this"));
75+
bus.unsubscribe(foo);
76+
bus.publish(MessageData.of("Only Bar should see this"));
77+
bus.publish(StoppingData.of(LocalDateTime.now()));
78+
}
79+
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/**
2+
* The MIT License
3+
* Copyright (c) 2014-2016 Ilkka Seppälä
4+
* <p>
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
* <p>
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
* <p>
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
package com.iluwatar.databus;
25+
26+
import java.util.HashSet;
27+
import java.util.Set;
28+
29+
/**
30+
* The Data-Bus implementation.
31+
*
32+
* <p>This implementation uses a Singleton.</p>
33+
*
34+
* @author Paul Campbell (pcampbell@kemitix.net)
35+
*/
36+
public class DataBus {
37+
38+
private static final DataBus INSTANCE = new DataBus();
39+
40+
private final Set<Member> listeners = new HashSet<>();
41+
42+
public static DataBus getInstance() {
43+
return INSTANCE;
44+
}
45+
46+
/**
47+
* Register a member with the data-bus to start receiving events.
48+
*
49+
* @param member The member to register
50+
*/
51+
public void subscribe(final Member member) {
52+
this.listeners.add(member);
53+
}
54+
55+
/**
56+
* Deregister a member to stop receiving events.
57+
*
58+
* @param member The member to deregister
59+
*/
60+
public void unsubscribe(final Member member) {
61+
this.listeners.remove(member);
62+
}
63+
64+
/**
65+
* Publish and event to all members.
66+
*
67+
* @param event The event
68+
*/
69+
public void publish(final DataType event) {
70+
event.setDataBus(this);
71+
listeners.forEach(listener -> listener.accept(event));
72+
}
73+
}

0 commit comments

Comments
 (0)