-
Notifications
You must be signed in to change notification settings - Fork 0
/
MessageSender.java
executable file
·130 lines (117 loc) · 5.34 KB
/
MessageSender.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import java.util.ArrayList;
/**
* This class implements the sender side of the data link layer.
* <p>
* The source code supplied here only contains a partial implementation.
* Your completed version must be submitted for assessment.
* <p>
* You only need to finish the implementation of the sendMessage
* method to complete this class. No other parts of this file need to
* be changed. Do NOT alter the constructor or interface of any public
* method. Do NOT put this class inside a package. You may add new
* private methods, if you wish, but do NOT create any new classes.
* Only this file will be processed when your work is marked.
*
* @author David W. Arnold
* @version 17th Oct 2019
*/
public class MessageSender
{
private final String startFrame = "<";
private final String frameType = "D";
private final String frameTypeEnd = "E";
// DO NOT ADD ANY MORE INSTANCE VARIABLES
// but it's okay to define constants here
private final int segLenLen = 2;
private final String fieldDelimiter = "-";
private final int checksumLen = 2;
private final String endFrame = ">";
private final int maximumMessage = 99;
private int mtu; // maximum transfer unit (frame length limit)
private FrameSender physicalLayer; // physical layer object
private TerminalStream terminal; // terminal stream manager
/**
* MessageSender constructor - DO NOT ALTER ANY PART OF THIS
* Create and initialize new MessageSender.
*
* @param mtu the maximum transfer unit (MTU)
* (the length of a frame must not exceed the MTU)
* @throws ProtocolException if error detected
*/
public MessageSender(int mtu) throws ProtocolException
{
// Initialize fields
// Create physical layer and terminal stream manager
this.mtu = mtu;
this.physicalLayer = new FrameSender();
this.terminal = new TerminalStream("MessageSender");
terminal.printlnDiag("data link layer ready (mtu = " + mtu + ")");
}
/**
* Send a single message - THIS IS THE ONLY METHOD YOU NEED TO MODIFY
*
* @param message the message to be sent. The message can be any
* length and may be empty but the string reference should not
* be null.
* @throws ProtocolException immediately without attempting to
* send any further frames if, and only if, the physical layer
* throws an exception or the given message can't be sent
* without breaking the rules of the protocol (including the MTU)
*/
public void sendMessage(String message) throws ProtocolException
{
// Report action to terminal
// Note the terminal messages aren't part of the protocol,
// they're just included to help with testing and debugging
terminal.printlnDiag(" sendMessage starting (message = \"" + message + "\")");
ArrayList<String> frames = new ArrayList<>();
int prefixLen = startFrame.length() + frameType.length() + fieldDelimiter.length() + segLenLen + fieldDelimiter.length();
int suffixLen = fieldDelimiter.length() + checksumLen + endFrame.length();
int maxMessSegLen = mtu - prefixLen - suffixLen;
if (maxMessSegLen < 0) {
throw new ProtocolException("MTU not large enough for sending a frame with an empty message segment.");
} else if (maxMessSegLen > maximumMessage) {
maxMessSegLen = maximumMessage;
}
while (message.length() > maxMessSegLen) {
String tmp = message.substring(0, maxMessSegLen);
frames.add(createFrame(tmp, frameType));
message = message.substring(maxMessSegLen);
}
frames.add(createFrame(message, frameTypeEnd));
// The following statement shows how the frame sender is invoked.
// At the moment it just passes a fixed string.
// sendMessage should split large messages into several smaller
// segments. Each segment must be encoded as a frame in the
// format specified. sendFrame will need to be called separately
// for each frame in turn. See the coursework specification
// and other class documentation for further info.
for (String frame : frames) {
physicalLayer.sendFrame(frame);
}
// Report completion of task
terminal.printlnDiag(" sendMessage finished");
}
private String createFrame(String message, String frmType)
{
String arithSum = frmType + fieldDelimiter + genSegLength(message) + fieldDelimiter + message + fieldDelimiter;
return startFrame + arithSum + genChecksum(arithSum) + endFrame;
}
private String genSegLength(String seg)
{
int len = seg.length();
String segLength = Integer.toString(len);
if (len < 10) {
segLength = "0" + segLength;
}
return segLength;
}
private String genChecksum(String string)
{
int total = 0;
for (char character : string.toCharArray()) {
total += character;
}
return Integer.toString(total).substring(Integer.toString(total).length() - 2);
}
}