jtulach@293
|
1 |
<!--
|
jtulach@293
|
2 |
|
jaroslav@358
|
3 |
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
|
jtulach@293
|
4 |
|
jaroslav@551
|
5 |
Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
|
jtulach@293
|
6 |
|
jaroslav@358
|
7 |
Oracle and Java are registered trademarks of Oracle and/or its affiliates.
|
jaroslav@358
|
8 |
Other names may be trademarks of their respective owners.
|
jtulach@293
|
9 |
|
jaroslav@358
|
10 |
The contents of this file are subject to the terms of either the GNU
|
jaroslav@358
|
11 |
General Public License Version 2 only ("GPL") or the Common
|
jaroslav@358
|
12 |
Development and Distribution License("CDDL") (collectively, the
|
jaroslav@358
|
13 |
"License"). You may not use this file except in compliance with the
|
jaroslav@358
|
14 |
License. You can obtain a copy of the License at
|
jaroslav@358
|
15 |
http://www.netbeans.org/cddl-gplv2.html
|
jaroslav@358
|
16 |
or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
|
jaroslav@358
|
17 |
specific language governing permissions and limitations under the
|
jaroslav@358
|
18 |
License. When distributing the software, include this License Header
|
jaroslav@358
|
19 |
Notice in each file and include the License file at
|
jaroslav@358
|
20 |
nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
|
jaroslav@358
|
21 |
particular file as subject to the "Classpath" exception as provided
|
jaroslav@358
|
22 |
by Oracle in the GPL Version 2 section of the License file that
|
jaroslav@358
|
23 |
accompanied this code. If applicable, add the following below the
|
jaroslav@358
|
24 |
License Header, with the fields enclosed by brackets [] replaced by
|
jaroslav@358
|
25 |
your own identifying information:
|
jaroslav@358
|
26 |
"Portions Copyrighted [year] [name of copyright owner]"
|
jaroslav@358
|
27 |
|
jaroslav@358
|
28 |
Contributor(s):
|
jaroslav@358
|
29 |
|
jaroslav@358
|
30 |
The Original Software is NetBeans. The Initial Developer of the Original
|
jaroslav@551
|
31 |
Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
|
jaroslav@358
|
32 |
|
jaroslav@358
|
33 |
If you wish your version of this file to be governed by only the CDDL
|
jaroslav@358
|
34 |
or only the GPL Version 2, indicate your decision by adding
|
jaroslav@358
|
35 |
"[Contributor] elects to include this software in this distribution
|
jaroslav@358
|
36 |
under the [CDDL or GPL Version 2] license." If you do not indicate a
|
jaroslav@358
|
37 |
single choice of license, a recipient has the option to distribute
|
jaroslav@358
|
38 |
your version of this file under either the CDDL, the GPL Version 2 or
|
jaroslav@358
|
39 |
to extend the choice of license to its licensees as provided above.
|
jaroslav@358
|
40 |
However, if you add GPL Version 2 code and therefore, elected the GPL
|
jaroslav@358
|
41 |
Version 2 license, then the option applies only if the new code is
|
jaroslav@358
|
42 |
made subject to such option by the copyright holder.
|
jtulach@293
|
43 |
|
jtulach@293
|
44 |
-->
|
jaroslav@291
|
45 |
<!DOCTYPE html>
|
jaroslav@291
|
46 |
<html>
|
jaroslav@291
|
47 |
<head>
|
jaroslav@291
|
48 |
<title>WebSockets via @OnReceive</title>
|
jaroslav@291
|
49 |
<meta charset="UTF-8">
|
jaroslav@291
|
50 |
<link rel="stylesheet" type="text/css" href="../../../../../stylesheet.css" title="Style">
|
jaroslav@291
|
51 |
</head>
|
jaroslav@291
|
52 |
<body>
|
jaroslav@291
|
53 |
<h1>Using <a href="../OnReceive.html">@OnReceive</a> to Communicate
|
jaroslav@291
|
54 |
via WebSockets Protocol</h1>
|
jaroslav@291
|
55 |
|
jaroslav@291
|
56 |
There is a simple, yet flexible way to communicate with a server
|
jaroslav@291
|
57 |
via <a href="http://www.w3.org/TR/websockets/">WebSockets protocol</a>.
|
jaroslav@291
|
58 |
The support can transfer any classes generated by
|
jaroslav@291
|
59 |
<a href="../Model.html">@Model</a> annotation and reuses already
|
jaroslav@291
|
60 |
existing <a href="../OnReceive.html">@OnReceive</a> infrastructure -
|
jaroslav@291
|
61 |
just defines detailed special behavior, which is described here.
|
jaroslav@291
|
62 |
|
jaroslav@291
|
63 |
<h3>Define JSON Class</h3>
|
jaroslav@291
|
64 |
|
jaroslav@291
|
65 |
The first step in using <em>WebSockets</em> is to create a model classes
|
jaroslav@291
|
66 |
to encapsulate communiation with the server. For example one for
|
jaroslav@291
|
67 |
sending requests and one for receiving replies:
|
jaroslav@291
|
68 |
<pre>
|
jaroslav@291
|
69 |
<a href="../Model.html">@Model</a>(className = "Comm", properties={})
|
jaroslav@291
|
70 |
<b>final class</b> Communication {
|
jaroslav@291
|
71 |
<a href="../Model.html">@Model</a>(className = "Request", properties = {
|
jaroslav@291
|
72 |
<a href="../Property.html">@Property</a>(name = "msg", type = MsgType<b>.class</b>),
|
jaroslav@291
|
73 |
<a href="../Property.html">@Property</a>(name = "username", type = String<b>.class</b>),
|
jaroslav@291
|
74 |
<a href="../Property.html">@Property</a>(name = "password", type = String<b>.class</b>),
|
jaroslav@291
|
75 |
<a href="../Property.html">@Property</a>(name = "gameId", type = String<b>.class</b>),
|
jaroslav@291
|
76 |
<a href="../Property.html">@Property</a>(name = "color", type = Color<b>.class</b>),
|
jaroslav@291
|
77 |
<a href="../Property.html">@Property</a>(name = "from", type = String<b>.class</b>),
|
jaroslav@291
|
78 |
<a href="../Property.html">@Property</a>(name = "to", type = String<b>.class</b>),
|
jaroslav@291
|
79 |
<a href="../Property.html">@Property</a>(name = "observer", type = boolean<b>.class</b>),
|
jaroslav@291
|
80 |
})
|
jaroslav@291
|
81 |
<b>static class</b> <em>RequestModel</em> {
|
jaroslav@291
|
82 |
}
|
jaroslav@291
|
83 |
|
jaroslav@291
|
84 |
<a href="../Model.html">@Model</a>(className = "Response", properties = {
|
jaroslav@291
|
85 |
<a href="../Property.html">@Property</a>(name = "msg", type = MsgType<b>.class</b>),
|
jaroslav@291
|
86 |
<a href="../Property.html">@Property</a>(name = "turn", type = Color<b>.class</b>),
|
jaroslav@291
|
87 |
<a href="../Property.html">@Property</a>(name = "color", type = Color<b>.class</b>),
|
jaroslav@291
|
88 |
<a href="../Property.html">@Property</a>(name = "gameId", type = String<b>.class</b>),
|
jaroslav@291
|
89 |
<a href="../Property.html">@Property</a>(name = "status", type = String<b>.class</b>),
|
jaroslav@291
|
90 |
<a href="../Property.html">@Property</a>(name = "moves", type = String<b>.class</b>, array = <b>true</b>),
|
jaroslav@291
|
91 |
<a href="../Property.html">@Property</a>(name = "from", type = String<b>.class</b>),
|
jaroslav@291
|
92 |
<a href="../Property.html">@Property</a>(name = "to", type = String<b>.class</b>),
|
jaroslav@291
|
93 |
})
|
jaroslav@291
|
94 |
<b>static class</b> <em>ResponseModel</em> {
|
jaroslav@291
|
95 |
}
|
jaroslav@291
|
96 |
|
jaroslav@291
|
97 |
<b>enum</b> <em>MsgType</em> {
|
jaroslav@291
|
98 |
CreateGame, QueryGames, SendMove, JoinGame, UpdateGame;
|
jaroslav@291
|
99 |
}
|
jaroslav@291
|
100 |
<b>enum</b> <em>Color</em> {
|
jaroslav@291
|
101 |
W, B;
|
jaroslav@291
|
102 |
}
|
jaroslav@291
|
103 |
}
|
jaroslav@291
|
104 |
</pre>
|
jaroslav@291
|
105 |
And then it is just a matter of creating the communication end point. As
|
jaroslav@291
|
106 |
usual with <a href="../OnReceive.html">@OnReceive</a> annotation one starts
|
jaroslav@291
|
107 |
with defining the response handler:
|
jaroslav@291
|
108 |
<pre>
|
jaroslav@291
|
109 |
<a href="../OnReceive.html">@OnReceive</a>(
|
jaroslav@291
|
110 |
data = <em>Request</em>.<b>class</b>,
|
jaroslav@291
|
111 |
url = "{url}",
|
jaroslav@291
|
112 |
method = <em>"WebSocket"</em>,
|
jaroslav@291
|
113 |
onError = "anErrorHappened"
|
jaroslav@291
|
114 |
)
|
jaroslav@291
|
115 |
<b>static void</b> queryServer(Comm c, Response r) {
|
jaroslav@291
|
116 |
<b>if</b> (r == null) {
|
jaroslav@291
|
117 |
// <em>connection stablished!</em>
|
jaroslav@291
|
118 |
<b>return</b>;
|
jaroslav@291
|
119 |
}
|
jaroslav@291
|
120 |
// <em>message arrived!</em>
|
jaroslav@291
|
121 |
<b>switch</b> (r.getMsg()) {
|
jaroslav@291
|
122 |
<b>case</b> CreateGame: /* do something */ <b>break</b>;
|
jaroslav@291
|
123 |
<b>case</b> QueryGames: /* do something */ <b>break</b>;
|
jaroslav@291
|
124 |
<b>case</b> SendMove: /* do something */ <b>break</b>;
|
jaroslav@291
|
125 |
<b>case</b> JoinGame: /* do something */ <b>break</b>;
|
jaroslav@291
|
126 |
<b>case</b> UpdateGame: /* do something */ <b>break</b>;
|
jaroslav@291
|
127 |
}
|
jaroslav@291
|
128 |
}
|
jaroslav@291
|
129 |
<b>static void</b> anErrorHappened(Comm c, Exception t) {
|
jaroslav@291
|
130 |
if (t == null) {
|
jaroslav@291
|
131 |
// <em>OK, connection has been closed</em>
|
jaroslav@291
|
132 |
} else {
|
jaroslav@291
|
133 |
// <em>handle the error t somehow</em>
|
jaroslav@291
|
134 |
}
|
jaroslav@291
|
135 |
}
|
jaroslav@291
|
136 |
</pre>
|
jaroslav@291
|
137 |
The <a href="http://www.w3.org/TR/websockets/">WebSockets</a> specification
|
jaroslav@291
|
138 |
usually defines what should happen <em>onopen, onmessage, onclose and onerror</em>.
|
jaroslav@291
|
139 |
All these messages are supported in the previous example as well:
|
jaroslav@291
|
140 |
<ul>
|
jaroslav@291
|
141 |
<li><b>onopen</b> - the <em>queryServer</em> method is called with
|
jaroslav@291
|
142 |
<code>null</code> message
|
jaroslav@291
|
143 |
</li>
|
jaroslav@291
|
144 |
<li><b>onmessage</b> - the <em>queryServer</em> method is called with
|
jaroslav@291
|
145 |
non-null message
|
jaroslav@291
|
146 |
</li>
|
jaroslav@291
|
147 |
<li><b>onclose</b> - the <em>anErrorHappened</em> method is called with
|
jaroslav@291
|
148 |
<code>null</code> exception
|
jaroslav@291
|
149 |
</li>
|
jaroslav@291
|
150 |
<li><b>onerror</b> - the <em>anErrorHappened</em> method is called with
|
jaroslav@291
|
151 |
non-null exception
|
jaroslav@291
|
152 |
</li>
|
jaroslav@291
|
153 |
</ul>
|
jaroslav@291
|
154 |
Using the <a href="../OnReceive.html">@OnReceive</a> annotation instructs
|
jaroslav@291
|
155 |
its associated annotation processor to add appropriate send method
|
jaroslav@291
|
156 |
into the generated <code>Comm</code> class. One can use it to establish communication,
|
jaroslav@291
|
157 |
send messages and close the communication channel. Here are three methods
|
jaroslav@291
|
158 |
showing how to do it:
|
jaroslav@291
|
159 |
<pre>
|
jaroslav@291
|
160 |
<b>static void </b>connect(Comm c) {
|
jaroslav@291
|
161 |
// open a websocket channel:
|
jaroslav@291
|
162 |
c.queryServer("ws://server/path", <b>null</b>);
|
jaroslav@291
|
163 |
// the method returns immediately and starts establishing the connection
|
jaroslav@291
|
164 |
// once that is finished either <b>onopen</b> or <b>onerror</b> type of
|
jaroslav@291
|
165 |
// message is delivered
|
jaroslav@291
|
166 |
}
|
jaroslav@291
|
167 |
|
jaroslav@291
|
168 |
<b>static void </b>sendMessage(Comm c, Request r) {
|
jaroslav@291
|
169 |
// sends the message to already openned websocket channel:
|
jaroslav@291
|
170 |
c.queryServer("ws://server/path", r);
|
jaroslav@291
|
171 |
}
|
jaroslav@291
|
172 |
|
jaroslav@291
|
173 |
<b>static void </b>disconnect(Comm c) {
|
jaroslav@291
|
174 |
// sending <code>null</code> again, closes the connection
|
jaroslav@291
|
175 |
c.queryServer("ws://server/path", <b>null</b>);
|
jaroslav@291
|
176 |
}
|
jaroslav@291
|
177 |
</pre>
|
jaroslav@291
|
178 |
One cannot change the URL while a connection is open otherwise one
|
jaroslav@291
|
179 |
risks <code>IllegalStateException</code> runtime exceptions. To connect
|
jaroslav@291
|
180 |
to different web socket server, one needs to close the connection first and
|
jaroslav@291
|
181 |
only later open new one with different URL.
|
jaroslav@291
|
182 |
<p>
|
jaroslav@291
|
183 |
Enjoy <em>WebSocket</em>s via <a href="../OnReceive.html">@OnReceive</a>!
|
jaroslav@291
|
184 |
</body>
|
jaroslav@291
|
185 |
</html>
|