1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.web.socket.sockjs.frame;
18
19 import java.nio.charset.Charset;
20
21 import org.springframework.util.StringUtils;
22
23
24
25
26
27
28
29 public class SockJsFrame {
30
31 public static final Charset CHARSET = Charset.forName("UTF-8");
32
33 private static final SockJsFrame OPEN_FRAME = new SockJsFrame("o");
34
35 private static final SockJsFrame HEARTBEAT_FRAME = new SockJsFrame("h");
36
37 private static final SockJsFrame CLOSE_GO_AWAY_FRAME = closeFrame(3000, "Go away!");
38
39 private static final SockJsFrame CLOSE_ANOTHER_CONNECTION_OPEN_FRAME = closeFrame(2010, "Another connection still open");
40
41
42 private final SockJsFrameType type;
43
44 private final String content;
45
46
47
48
49
50
51 public SockJsFrame(String content) {
52 StringUtils.hasText(content);
53 if ("o".equals(content)) {
54 this.type = SockJsFrameType.OPEN;
55 this.content = content;
56 }
57 else if ("h".equals(content)) {
58 this.type = SockJsFrameType.HEARTBEAT;
59 this.content = content;
60 }
61 else if (content.charAt(0) == 'a') {
62 this.type = SockJsFrameType.MESSAGE;
63 this.content = (content.length() > 1 ? content : "a[]");
64 }
65 else if (content.charAt(0) == 'm') {
66 this.type = SockJsFrameType.MESSAGE;
67 this.content = (content.length() > 1 ? content : "null");
68 }
69 else if (content.charAt(0) == 'c') {
70 this.type = SockJsFrameType.CLOSE;
71 this.content = (content.length() > 1 ? content : "c[]");
72 }
73 else {
74 throw new IllegalArgumentException("Unexpected SockJS frame type in content=\"" + content + "\"");
75 }
76 }
77
78 public static SockJsFrame openFrame() {
79 return OPEN_FRAME;
80 }
81
82 public static SockJsFrame heartbeatFrame() {
83 return HEARTBEAT_FRAME;
84 }
85
86 public static SockJsFrame messageFrame(SockJsMessageCodec codec, String... messages) {
87 String encoded = codec.encode(messages);
88 return new SockJsFrame(encoded);
89 }
90
91 public static SockJsFrame closeFrameGoAway() {
92 return CLOSE_GO_AWAY_FRAME;
93 }
94
95 public static SockJsFrame closeFrameAnotherConnectionOpen() {
96 return CLOSE_ANOTHER_CONNECTION_OPEN_FRAME;
97 }
98
99 public static SockJsFrame closeFrame(int code, String reason) {
100 return new SockJsFrame("c[" + code + ",\"" + reason + "\"]");
101 }
102
103
104
105
106
107 public SockJsFrameType getType() {
108 return this.type;
109 }
110
111
112
113
114 public String getContent() {
115 return this.content;
116 }
117
118
119
120
121 public byte[] getContentBytes() {
122 return this.content.getBytes(CHARSET);
123 }
124
125
126
127
128
129
130 public String getFrameData() {
131 if (SockJsFrameType.OPEN == getType() || SockJsFrameType.HEARTBEAT == getType()) {
132 return null;
133 }
134 else {
135 return getContent().substring(1);
136 }
137 }
138
139
140 @Override
141 public boolean equals(Object other) {
142 if (this == other) {
143 return true;
144 }
145 if (!(other instanceof SockJsFrame)) {
146 return false;
147 }
148 return (this.type.equals(((SockJsFrame) other).type) && this.content.equals(((SockJsFrame) other).content));
149 }
150
151 @Override
152 public int hashCode() {
153 return this.content.hashCode();
154 }
155
156 @Override
157 public String toString() {
158 String result = this.content;
159 if (result.length() > 80) {
160 result = result.substring(0, 80) + "...(truncated)";
161 }
162 return "SockJsFrame content='" + result.replace("\n", "\\n").replace("\r", "\\r") + "'";
163 }
164
165 }