forked from eclipse-keyple/keyple-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKeypleRemoteSe_UserGuide.html
More file actions
296 lines (204 loc) · 11.2 KB
/
KeypleRemoteSe_UserGuide.html
File metadata and controls
296 lines (204 loc) · 11.2 KB
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
<h1>Remote SE Guide</h1>
<h2>Why do I need Remote SE</h2>
<p>
The Remote SE architecture allows a device to communicate remotely with a <strong>SE Reader</strong> plugged into another device.
</p>
<p>
It is mostly used to host the Ticketing Logic on a remote server. The end user terminal allows the server to connect to its local <strong>SE Reader </strong>via the Remote Se API, then the server can communicate with the Reader as if it was a local reader.
</p>
<p>
In a Calypso context, it is useful when a SAM reader and a PO reader are not connected to the same terminal. With the Remote Se API, you can open Calypso transaction within a distributed architecture.
</p>
<h2>How does it work</h2>
<p>
The architecture is based on a Slave-Master principle. The slave hosts a local SE reader that will be accessed remotely by the Master.
</p>
<p>
The components of the Remote Se Architecture don’t rely on a given transport layer, either Slave and Master can be a client or a server of any protocol (ie : http, websocket).
</p>
<p>
Example of a use case
</p>
<p>
A server (let's identify it <strong>server1</strong>) needs to communicate with other terminals reader (<strong>client2</strong>). To give access to it's local reader, <strong>client2</strong> should open a session to <strong>server1</strong> via the <code>SlaveAPI#connect()</code> method. Doing this, <strong>server1</strong> receives the possibility to communicate with the local reader of <strong>client2</strong>. In this scenario <strong>server1</strong> is a Master node and <strong>client2</strong> is a Slave node.
</p>
<p>
When <strong>client2</strong> opens successfully a session to <strong>server1</strong>, a <code>VirtualReader</code> is created on <strong>server1</strong> side. This <code>VirtualReader</code> is viewed as a local reader <strong>server1</strong>, in fact, the <code>VirtualReader</code> acts as a proxy to the <code>SeReader</code> hosted on <strong>client2</strong>.
</p>
<h2>KeypleDto</h2>
<p>
The Remote Se Architecture is based on a RPC architecture. When a Master node invokes a transmit method on a Virtual Reader, this method is called on the corresponding local Reader on the Slave node.
</p>
<p>
The RPC protocol of the Remote Se Architecture is based on Json messages sent back and forth between the Slaves and the Master.
</p>
<p>
Those messages share a common structure called <strong>KeypleDto</strong> whose definition is specified here after.
</p>
<p>
The definition of the keypleDto follows the Json-RPC 1.0 specification.
</p>
<pre class="prettyprint">KeypleDto definition
/* Metadata */
String requesterNodeId; // Requester Node Id
String targetNodeId; // Receiver Node Id
String sessionId; // Master reader session
String nativeReaderName; // Native reader name
String virtualReaderName; // Virtual reader name
/* API call */
String id; // Id of the request
String action; // API methods to be called (listed in the object RemoteMethodName)
String body; // Arguments of the API (json-serialized)
Boolean isRequest; // Is a request or a response</pre>
<h2>User guide</h2>
<p>
To establish a connection with the master, the slave device must use the <strong>SlaveAPI</strong>.
</p>
<p>
By passing a local reader to the connectReader, the slave will contact the master resulting in the opening of a virtual session.
</p>
<p>
During this session, a Virtual reader is available on the master side. Every apdu command sent to the Virtual Reader will be transferred to the Local reader and the response sent back to the Virtual reader
</p>
<p>
<strong>VirtualReader</strong> are created by the <strong>RemoteSePlugin</strong> on Master node when a local reader initiates a connection.
</p>
<pre class="prettyprint">Slave API
connectReader(SeReader localReader) : connect a local reader to the master node
disconnectReader(String sessionId, String nativeReaderName) : disconnect a connected reader from the master node
Master API
RemoteSePlugin getPlugin() : get the remote se plugin
On Master node the main object is the VirtualReader
It can be manipulated as any SeReader
Every command is transferred to the local reader
It is accessible from the RemoteSe Plugin</pre>
<h2>Configuration</h2>
<p>
To allow the slave and master to exchange KeypleDto, a transport layer should be implemented via simple node-to-node layout. Both SlaveAPI and MasterAPI needs a DtoNode to be functional.
</p>
<p>
DtoNode can be implemented in top of websocket protocol or http webservice protocol. As Slave and Master have the initiative to send keypleDto, it is preferred to provide a 2-way communication protocol.
</p>
<p>
In case of http webservice, a polling mechanism can be implemented so the server can send messages to the client.
</p>
<p>
<img src="img/KeypleRemoteSe_DtoNode.png" width="" alt="alt_text" title="image_tooltip">
</p>
<h2>Architecture overview</h2>
<p>
<img src="img/KeypleRemoteSe_Architecture.png" width="" alt="alt_text" title="image_tooltip">
</p>
<h2>Quickstart Guide</h2>
<h3>Configure Master API with a DtoNode</h3>
<p>
In this quickstart guide, we will use a pre-built transport layer for the Remote Se Architecture.
</p>
<p>
This transport layer is built upon a Webservice protocol with polling. It is available on the remotese example projects under the package ‘transport”.
</p>
<p>
The MasterAPI will be instanciated with the ServerNode of the WsPollingRetrofit Transport.
</p>
<p>
The ServerNode component of this transport is a self contained web server based on the sun jdk 6.
</p>
<pre class="prettyprint">/* Configure the server Dto Node with a unique nodeId */
ServerNode node = new WsPollingRetrofitFactory("master1").getServer()
/* Start the server */
node.start()
/* Create a MasterAPI bound to this DtoNode */
MasterAPI masterAPI = new MasterAPI(SeProxyService.getInstance(), node);</pre>
<h3>Configure Slave API with a DtoNode</h3>
<p>
On the other hand, the slave we will instanciate the SlaveAPI with the clientNode of the transport with the Master node id, it will connect to.
</p>
<pre class="prettyprint">/* Configure the client Dto Node layer with the master node it will connect to and a unique slave node id*/
ClientNode node = new WsPollingRetrofitFactory("master1").getClient("client1")
/* Establish connection */
node.connect()
/* Create the SlaveAPI */
SlaveAPI slaveAPI = new SlaveAPI(SeProxyService.getInstance(), node, "master1");</pre>
<h3>Connect a local Reader to Master</h3>
<p>
The next step is to connect a SeReader from the slave node by calling the SlaveAPI connectReader method.
</p>
<p>
In this example we will use a StubReader instanciated from the Stub Plugin.<br>
<br>
Once the local reader is connected, it can be used by the Master as a Virtual Reader.
</p>
<pre class="prettyprint">/* Slave */
StubPlugin stubPlugin = StubPlugin.getInstance();
stubPlugin.plugStubReader("stubClientSlave", true);
/* retrieve SeReader Instance */
SeReader localReader = stubPlugin.getReader("stubClientSlave");
/* connect local Reader to Master */
slaveAPI.connectReader(localReader)</pre>
<h3>Listen for Reader Events on Master side</h3>
<p>
To get notified of a SeReader connection, you can observe the Remote Se Plugin, RsePlugin for events such as : <strong><em>READER_CONNECTED, READER_DISCONNECTED</em></strong>
</p>
<p>
</p>
<p>
To get notified of a Se inserted into a remote Se Reader, you can observe the corresponding Virtual Reader for events such as : <strong><em>SE_MATCHED, SE_INSERTED, SE_REMOVED</em></strong>
</p>
<pre class="prettyprint">/* Master */
RsePlugin rsePlugin = masterAPI.getPlugin();
rsePlugin.addObserver(this);
public void update(final Object o) {
// Receive a PluginEvent
if (o instanceof PluginEvent) {
switch (o.getEventType()) {
case READER_CONNECTED: break;
case READER_DISCONNECTED:break;}
}
// ReaderEvent
else if (o instanceof ReaderEvent) {
switch (o.getEventType()) {
case SE_MATCHED:break;
case SE_INSERTED:break;
case SE_REMOVED:break;
}</pre>
<h2>Developer Guide</h2>
<h3>KeypleDto type</h3>
<p>
KeypleDto are RPC messages sent back and forth between Slave nodes and the Master node. They transport a piece of information that can be a Request, a Response, an Error or a Notification. A fifth type is used internally : NoResponse.
</p>
<ul>
<li><strong>Request</strong> : it transports the remote procedure invocation. It can be a ProxyReader method such as a transmit() or a remoteSe specific method like connectReader. The name of the method is in the “action” field, the “body” wraps the parameters of the method. Each Request is assigned a unique “id” to be easily retrieved.
<li><strong>Response</strong> : it transports the remote procedure response, if it is not an error. It matches a Request and will be sent to the node that originated the Request. The “body” field contains the response object(s).
<li><strong>Error (Exception)</strong> : Same as Response but it transports an error resulting from the Request. The “body” field contains a Java Exception
<li><strong>Notification</strong> : it transports a notification such as a ReaderEvent. No response is expected from a notification. The ‘id’ field is empty
<li><strong>NoResponse</strong> : it should not be sent. This keypleDto is a stop semaphore to notify DtoNode that the received keypleDto do not expect a response back.
</li>
</ul>
<h3>How Reader Events are processed in Remote Se Architecture</h3>
<p>
When a Reader Event (SE_INSERTED) is thrown by a local reader, if this local reader is connected to a Master, the event is then propagated to the virtual reader on the Master node.
</p>
<p>
When received by the virtual reader, the event is transformed to be seen by the Master Application as an event thrown by the virtual reader. The fields reader name and plugin name are converted to match the Virtual Reader name and the Remote SE Plugin name.
</p>
<h3>Transport implementation</h3>
<h4>TransportDto vs KeypleDto</h4>
<p>
<code>KeypleDto</code> is the object that contains the information about the remote invocation, they are built and processed by the plugin, there is no need to modify them.
</p>
<p>
Users needs to implement (and personalize if needed) <code>TransportDto</code> which is an envelop for a KeypleDto. It allows to enrich a KeypleDto with information on the transport implementation to allow back and forth communication. (for instance a callback url)
</p>
<h4>
DtoNode</h4>
<p>
<code>DtoNode</code> is a convenient interface, it links a <code>DtoSender</code> with a <code>DtoHandler</code> to create a unique point of contact.
</p>
<h4>DtoSender</h4>
<p>
<code>DtoSender</code> is the component responsible for sending the TransportDto to the other terminal.
</p>
<h4>DtoHandler</h4>
<p>
<code>DtoHandler</code> interface is implemented by both <code>SlaveAPI</code> (Slave side) and <code>MasterAPI</code> (Master side). Both services waits for a KeypleDto, process it, and will return a KeypleDto as a response (if any). You should link a <code>DtoNode</code> to both <code>SlaveAPI</code> and <code>MasterAPI</code> to make them communicate.
</p>