TDDC32 Design and implementation of a software module in Java
Lab 2 - Advanced Java Programming
Your task
Your task is to write a program that implements the following producer-consumer scenario, and which has a GUI (using swing) that complies to the following descriptions.
The scenario is as follows: There are 3 producers and 3 consumers that
use a bounded buffer of capacity 4 (characters).
The producers produce
one character (letter) at a time, that is set in the bounded buffer
if there is space available.
The consumers take one character at a
time, if available, and display it.
Both the producers and the
consumers are executing concurrently, hence you will need to use
threads to implement this.
The bounded buffer should behave like a
queue, that is, a new character is added on one end, "pushing" the
other towards the opposite end. The characters are consumed (read and
removed) from the end opposite to insertion.
To simulate
buffer-handling, whenever a producer or a consumer gets access to the
buffer, it should be delayed with a certain (common) value, that can
be set from the GUI.
To simulate producing/consuming time,
before/after each successful access to the buffer the
producers/consumers should be delayed with a certain value (separate
for the 6 threads), that can also be set from the GUI.
Remember that
only one thread should be manipulating the bounded buffer at the same
time, so that insertion/removal inconsistencies do not appear.
The GUI should look as follows:
- On the left side of the GUI window you should have 3 viewports stacked on top of each other that present the activity of the producers. Each producer should have a text area where the characters already produced are displayed. In addition, each producer should have a text field that displays the status of the producer. The status can be one of the following four: "PRODUCING" - when the producer is delayed simulating production, "WAITING_ON_BUFFER_ACCESS" - when it waits to get access to the buffer, "WAITING_ON_BUFFER_NOT_FULL" - when it tried to set the value in the buffer, but the buffer was full, "MANIPULATING_BUFFER" - when it inserts in the buffer (and is delayed there).
- On the right side of the GUI window you should have 3 viewports stacked on top of each other that present the activity of the consumers. Each consumer should have a text area where the consumed characters are displayed. In addition, each consumer should have a text field that displays the status of the consumer. The status can be one of the following four: "CONSUMING" - when the consumer is delayed simulating consumption, "WAITING_ON_BUFFER_ACCESS" - when it waits to get access to the buffer, "WAITING_ON_BUFFER_NOT_EMPTY" - when it tried to get a value from the buffer, but the buffer was empty, "MANIPULATING_BUFFER" - when it removes from the buffer (and is delayed there).
- Both producers and consumers should have a text field or a slider where the user can insert the delay values that simulate production/consumption. To be able to differentiate between characters produced from different producers, each producer should use a different colour for their characters, i.e red for nr.1, green for nr.2 and blue for nr.3. This should be also visible in the consumer text areas.
- In the middle of the GUI window you should present the content of the buffer (e.g. 4 boxes, with their respective characters inside, or empty). When a producer/consumer is manipulating the buffer, it's name should be displayed and the character that is added/removed should be highlighted. There should be a text field available where the user can insert the delay value that simulates buffer manipulation (which applies to all producers/consumers when they get access to the buffer). It should also be possible for the user to choose a manual manipulation mode, where he clicks on a button for allowing the current thread to exit the buffer immediately (overriding the remaining manipulation delay time).
Recommended steps
We recommend to solve the lab in the following steps:
1) First write pseudocode for the Producer/Consumer/BoundedBuffer objects where you should have all the synchronisation routines (sleep(), wait(), notify(), notifyall(), synchronized methods). Most likely you will want to have two methods in the BoundedBuffer, to be accessed by the producer and consumer.
2) Fully implement the base objects.
3) Create the GUI and connect it to the base objects.
Note: steps 2) and 3) could be implemented in parallel for better visualisation of the behaviour of your program.
Hints and Guidelines
Here follows some hints and guidelines to help you streamline the GUI development. It can be quite time-consuming to search through the Java API, so next we present some tips on how to construct the GUI. Of course, use them only if you need them.
1) A nice layout manager is BoxLayout, which lets you add
components stacked either vertically or horizontally. A vertical
example:
container.setLayout(newBoxLayout(container,BoxLayout.Y_AXIS));
Inside, components can be aligned horizontally or vertically, for
instance a centered horizontal alignment looks like this:
component.setAlignmentX(Component.CENTER_ALIGNMENT);
For any component you can specify borders to make it clear where the
boundaries are, e.g.: component.setBorder(new
LineBorder(Color.BLACK,2));
Between useful components you
can insert struts so they don't appear too close to each other, e.g.:
Box.createHorisontalStrut(10);
Don't forget that for any component
you can change foreground (text) and background colors and that you
can hierarchically use panels to nicely layout the GUI.
2) Finding a way to display colored characters next to each other (in
the consumer) can be a little bit tricky. Hence, it is OK if you don't
use colors (e.g. red for producer 1, green for producer 2, and blue
for producer 3), and instead display the number of the producer
immediately after the character, like in "c3". This will allow you to
use the JTextArea component. If you want colored output
you need to use a JTextPane. Look at the following
example of usage:
JTextPane txtPane = new JTextPane(); txtPane.setPreferredSize(new Dimension(300,50)); txtPane.setEditable(false); JScrollPane sp = new JScrollPane(txtPane); ... Document doc = txtPane.getDocument(); MutableAttributeSet ats = txtPane.getInputAttributes(); //set color: StyleConstants.setForeground(ats, Color.GREEN); //append "a", in green color: doc.insertString(doc.getEndPosition().getOffset()-1,"a",ats);
3) About state "PRODUCING" and "MANIPULATING_BUFFER". State
"PRODUCING" (and the respective delay) simulates the production, and
happens before the thread wants to get access to the buffer in order
to insert the value. The state "MANIPULATING_BUFFER" (and the
respective delay) simulates the insertion in the buffer and happens
after the thread has entered the buffer. Similarly for the consumer.
Voluntary stuff (not required)
If you feel like getting a nice exercise, put the producers and the
bounded buffer on a server and the consumers on client machines and
make the communication between bounded buffer and consumers to use TCP
sockets.
Page responsible: Tommy Färnqvist
Last updated: 2013-01-09
