blob: 2935747e32852a13dd244e99b4bbe3c09ea6512f [file] [log] [blame]
Jake Farrell27274222011-11-10 20:32:44 +00001(*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *)
19
20 unit Thrift.Server;
21
Jens Geyer26ef7432013-09-23 22:01:20 +020022{$I-} // prevent annoying errors with default log delegate and no console
23
Jake Farrell27274222011-11-10 20:32:44 +000024interface
25
26uses
Jens Geyer26ef7432013-09-23 22:01:20 +020027 Windows, SysUtils,
Jake Farrell27274222011-11-10 20:32:44 +000028 Thrift,
29 Thrift.Protocol,
30 Thrift.Transport;
31
32type
Jens Geyer01640402013-09-25 21:12:21 +020033 IServerEvents = interface
34 ['{9E2A99C5-EE85-40B2-9A52-2D1722B18176}']
35 // Called before the server begins.
36 procedure PreServe;
37 // Called when the server transport is ready to accept requests
38 procedure PreAccept;
39 // Called when a new client has connected and the server is about to being processing.
40 function CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
41 end;
42
43
Jake Farrell27274222011-11-10 20:32:44 +000044 IServer = interface
Jens Geyer01640402013-09-25 21:12:21 +020045 ['{ADC46F2D-8199-4D1C-96D2-87FD54351723}']
Jake Farrell27274222011-11-10 20:32:44 +000046 procedure Serve;
47 procedure Stop;
Jens Geyer01640402013-09-25 21:12:21 +020048
49 function GetServerEvents : IServerEvents;
50 procedure SetServerEvents( const value : IServerEvents);
51
52 property ServerEvents : IServerEvents read GetServerEvents write SetServerEvents;
Jake Farrell27274222011-11-10 20:32:44 +000053 end;
54
55 TServerImpl = class abstract( TInterfacedObject, IServer )
56 public
57 type
Roger Meier333bbf32012-01-08 21:51:08 +000058 TLogDelegate = reference to procedure( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +000059 protected
60 FProcessor : IProcessor;
61 FServerTransport : IServerTransport;
62 FInputTransportFactory : ITransportFactory;
63 FOutputTransportFactory : ITransportFactory;
64 FInputProtocolFactory : IProtocolFactory;
65 FOutputProtocolFactory : IProtocolFactory;
66 FLogDelegate : TLogDelegate;
Jens Geyer01640402013-09-25 21:12:21 +020067 FServerEvents : IServerEvents;
Jake Farrell27274222011-11-10 20:32:44 +000068
Roger Meier333bbf32012-01-08 21:51:08 +000069 class procedure DefaultLogDelegate( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +000070
Jens Geyer01640402013-09-25 21:12:21 +020071 function GetServerEvents : IServerEvents;
72 procedure SetServerEvents( const value : IServerEvents);
73
Jake Farrell27274222011-11-10 20:32:44 +000074 procedure Serve; virtual; abstract;
75 procedure Stop; virtual; abstract;
76 public
77 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000078 const AProcessor :IProcessor;
79 const AServerTransport: IServerTransport;
80 const AInputTransportFactory : ITransportFactory;
81 const AOutputTransportFactory : ITransportFactory;
82 const AInputProtocolFactory : IProtocolFactory;
83 const AOutputProtocolFactory : IProtocolFactory;
84 const ALogDelegate : TLogDelegate
Jake Farrell27274222011-11-10 20:32:44 +000085 ); overload;
86
Jens Geyer01640402013-09-25 21:12:21 +020087 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000088 const AProcessor :IProcessor;
89 const AServerTransport: IServerTransport
Jens Geyerd5436f52014-10-03 19:50:38 +020090 ); overload;
Jake Farrell27274222011-11-10 20:32:44 +000091
92 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000093 const AProcessor :IProcessor;
94 const AServerTransport: IServerTransport;
95 const ALogDelegate: TLogDelegate
Jake Farrell27274222011-11-10 20:32:44 +000096 ); overload;
97
98 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000099 const AProcessor :IProcessor;
100 const AServerTransport: IServerTransport;
101 const ATransportFactory : ITransportFactory
Jake Farrell27274222011-11-10 20:32:44 +0000102 ); overload;
103
104 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +0000105 const AProcessor :IProcessor;
106 const AServerTransport: IServerTransport;
107 const ATransportFactory : ITransportFactory;
108 const AProtocolFactory : IProtocolFactory
Jake Farrell27274222011-11-10 20:32:44 +0000109 ); overload;
110 end;
111
112 TSimpleServer = class( TServerImpl)
113 private
114 FStop : Boolean;
115 public
Roger Meier333bbf32012-01-08 21:51:08 +0000116 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport); overload;
117 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000118 ALogDel: TServerImpl.TLogDelegate); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000119 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
120 const ATransportFactory: ITransportFactory); overload;
121 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
122 const ATransportFactory: ITransportFactory; const AProtocolFactory: IProtocolFactory); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000123
124 procedure Serve; override;
125 procedure Stop; override;
126 end;
127
128
129implementation
130
131{ TServerImpl }
132
Roger Meier333bbf32012-01-08 21:51:08 +0000133constructor TServerImpl.Create( const AProcessor: IProcessor;
134 const AServerTransport: IServerTransport; const ALogDelegate: TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000135var
136 InputFactory, OutputFactory : IProtocolFactory;
137 InputTransFactory, OutputTransFactory : ITransportFactory;
138
139begin
140 InputFactory := TBinaryProtocolImpl.TFactory.Create;
141 OutputFactory := TBinaryProtocolImpl.TFactory.Create;
142 InputTransFactory := TTransportFactoryImpl.Create;
143 OutputTransFactory := TTransportFactoryImpl.Create;
144
Jens Geyer01640402013-09-25 21:12:21 +0200145 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000146 Create(
147 AProcessor,
148 AServerTransport,
149 InputTransFactory,
150 OutputTransFactory,
151 InputFactory,
152 OutputFactory,
153 ALogDelegate
154 );
155end;
156
Roger Meier333bbf32012-01-08 21:51:08 +0000157constructor TServerImpl.Create(const AProcessor: IProcessor;
158 const AServerTransport: IServerTransport);
Jake Farrell27274222011-11-10 20:32:44 +0000159var
160 InputFactory, OutputFactory : IProtocolFactory;
161 InputTransFactory, OutputTransFactory : ITransportFactory;
162
163begin
164 InputFactory := TBinaryProtocolImpl.TFactory.Create;
165 OutputFactory := TBinaryProtocolImpl.TFactory.Create;
166 InputTransFactory := TTransportFactoryImpl.Create;
167 OutputTransFactory := TTransportFactoryImpl.Create;
168
Jens Geyerd5436f52014-10-03 19:50:38 +0200169 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000170 Create(
171 AProcessor,
172 AServerTransport,
173 InputTransFactory,
174 OutputTransFactory,
175 InputFactory,
176 OutputFactory,
177 DefaultLogDelegate
178 );
179end;
180
Roger Meier333bbf32012-01-08 21:51:08 +0000181constructor TServerImpl.Create(const AProcessor: IProcessor;
182 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000183var
184 InputProtocolFactory : IProtocolFactory;
185 OutputProtocolFactory : IProtocolFactory;
186begin
187 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
188 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
189
Jens Geyerd5436f52014-10-03 19:50:38 +0200190 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000191 Create( AProcessor, AServerTransport, ATransportFactory, ATransportFactory,
192 InputProtocolFactory, OutputProtocolFactory, DefaultLogDelegate);
193end;
194
Roger Meier333bbf32012-01-08 21:51:08 +0000195constructor TServerImpl.Create(const AProcessor: IProcessor;
196 const AServerTransport: IServerTransport;
197 const AInputTransportFactory, AOutputTransportFactory: ITransportFactory;
198 const AInputProtocolFactory, AOutputProtocolFactory: IProtocolFactory;
199 const ALogDelegate : TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000200begin
Jens Geyer718f6ee2013-09-06 21:02:34 +0200201 inherited Create;
Jake Farrell27274222011-11-10 20:32:44 +0000202 FProcessor := AProcessor;
203 FServerTransport := AServerTransport;
204 FInputTransportFactory := AInputTransportFactory;
205 FOutputTransportFactory := AOutputTransportFactory;
206 FInputProtocolFactory := AInputProtocolFactory;
207 FOutputProtocolFactory := AOutputProtocolFactory;
208 FLogDelegate := ALogDelegate;
209end;
210
Roger Meier333bbf32012-01-08 21:51:08 +0000211class procedure TServerImpl.DefaultLogDelegate( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +0000212begin
Jens Geyer26ef7432013-09-23 22:01:20 +0200213 try
214 Writeln( str);
215 if IoResult <> 0 then OutputDebugString(PChar(str));
216 except
217 OutputDebugString(PChar(str));
218 end;
Jake Farrell27274222011-11-10 20:32:44 +0000219end;
220
Roger Meier333bbf32012-01-08 21:51:08 +0000221constructor TServerImpl.Create( const AProcessor: IProcessor;
222 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
223 const AProtocolFactory: IProtocolFactory);
Jake Farrell806d2982011-10-26 02:33:31 +0000224begin
Jens Geyer01640402013-09-25 21:12:21 +0200225 //no inherited;
Jake Farrell806d2982011-10-26 02:33:31 +0000226 Create( AProcessor, AServerTransport,
227 ATransportFactory, ATransportFactory,
228 AProtocolFactory, AProtocolFactory,
229 DefaultLogDelegate);
230end;
231
Jens Geyer01640402013-09-25 21:12:21 +0200232
233function TServerImpl.GetServerEvents : IServerEvents;
234begin
235 result := FServerEvents;
236end;
237
238
239procedure TServerImpl.SetServerEvents( const value : IServerEvents);
240begin
241 // if you need more than one, provide a specialized IServerEvents implementation
242 FServerEvents := value;
243end;
244
245
Jake Farrell806d2982011-10-26 02:33:31 +0000246{ TSimpleServer }
Jake Farrell27274222011-11-10 20:32:44 +0000247
Roger Meier333bbf32012-01-08 21:51:08 +0000248constructor TSimpleServer.Create( const AProcessor: IProcessor;
249 const AServerTransport: IServerTransport);
Jake Farrell27274222011-11-10 20:32:44 +0000250var
251 InputProtocolFactory : IProtocolFactory;
252 OutputProtocolFactory : IProtocolFactory;
253 InputTransportFactory : ITransportFactory;
254 OutputTransportFactory : ITransportFactory;
255begin
256 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
257 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
258 InputTransportFactory := TTransportFactoryImpl.Create;
259 OutputTransportFactory := TTransportFactoryImpl.Create;
260
261 inherited Create( AProcessor, AServerTransport, InputTransportFactory,
262 OutputTransportFactory, InputProtocolFactory, OutputProtocolFactory, DefaultLogDelegate);
263end;
264
Roger Meier333bbf32012-01-08 21:51:08 +0000265constructor TSimpleServer.Create( const AProcessor: IProcessor;
266 const AServerTransport: IServerTransport; ALogDel: TServerImpl.TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000267var
268 InputProtocolFactory : IProtocolFactory;
269 OutputProtocolFactory : IProtocolFactory;
270 InputTransportFactory : ITransportFactory;
271 OutputTransportFactory : ITransportFactory;
272begin
273 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
274 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
275 InputTransportFactory := TTransportFactoryImpl.Create;
276 OutputTransportFactory := TTransportFactoryImpl.Create;
277
278 inherited Create( AProcessor, AServerTransport, InputTransportFactory,
279 OutputTransportFactory, InputProtocolFactory, OutputProtocolFactory, ALogDel);
280end;
281
Roger Meier333bbf32012-01-08 21:51:08 +0000282constructor TSimpleServer.Create( const AProcessor: IProcessor;
283 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000284begin
285 inherited Create( AProcessor, AServerTransport, ATransportFactory,
286 ATransportFactory, TBinaryProtocolImpl.TFactory.Create, TBinaryProtocolImpl.TFactory.Create, DefaultLogDelegate);
287end;
288
Roger Meier333bbf32012-01-08 21:51:08 +0000289constructor TSimpleServer.Create( const AProcessor: IProcessor;
290 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
291 const AProtocolFactory: IProtocolFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000292begin
293 inherited Create( AProcessor, AServerTransport, ATransportFactory,
294 ATransportFactory, AProtocolFactory, AProtocolFactory, DefaultLogDelegate);
295end;
296
297procedure TSimpleServer.Serve;
298var
299 client : ITransport;
300 InputTransport : ITransport;
301 OutputTransport : ITransport;
302 InputProtocol : IProtocol;
303 OutputProtocol : IProtocol;
Jens Geyer01640402013-09-25 21:12:21 +0200304 context : IProcessorEvents;
Jake Farrell27274222011-11-10 20:32:44 +0000305begin
306 try
307 FServerTransport.Listen;
308 except
309 on E: Exception do
310 begin
311 FLogDelegate( E.ToString);
312 end;
313 end;
314
Jens Geyer01640402013-09-25 21:12:21 +0200315 if FServerEvents <> nil
316 then FServerEvents.PreServe;
317
Jake Farrell27274222011-11-10 20:32:44 +0000318 client := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000319 while (not FStop) do
320 begin
321 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200322 // clean up any old instances before waiting for clients
323 InputTransport := nil;
324 OutputTransport := nil;
325 InputProtocol := nil;
326 OutputProtocol := nil;
327
Jens Geyer3e8d9272014-09-14 20:10:40 +0200328 // close any old connections before before waiting for new clients
329 if client <> nil then try
330 try
331 client.Close;
332 finally
333 client := nil;
334 end;
335 except
336 // catch all, we can't do much about it at this point
337 end;
338
Jens Geyer01640402013-09-25 21:12:21 +0200339 client := FServerTransport.Accept( procedure
340 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200341 if FServerEvents <> nil
Jens Geyer01640402013-09-25 21:12:21 +0200342 then FServerEvents.PreAccept;
Jens Geyerd5436f52014-10-03 19:50:38 +0200343 end);
344
345 if client = nil then begin
346 if FStop
347 then Abort // silent exception
348 else raise TTransportException.Create( 'ServerTransport.Accept() may not return NULL' );
349 end;
350
Jake Farrell27274222011-11-10 20:32:44 +0000351 FLogDelegate( 'Client Connected!');
Jens Geyer06045cf2013-03-27 20:26:25 +0200352
Jake Farrell27274222011-11-10 20:32:44 +0000353 InputTransport := FInputTransportFactory.GetTransport( client );
354 OutputTransport := FOutputTransportFactory.GetTransport( client );
355 InputProtocol := FInputProtocolFactory.GetProtocol( InputTransport );
356 OutputProtocol := FOutputProtocolFactory.GetProtocol( OutputTransport );
Jens Geyer01640402013-09-25 21:12:21 +0200357
358 if FServerEvents <> nil
359 then context := FServerEvents.CreateProcessingContext( InputProtocol, OutputProtocol)
360 else context := nil;
361
362 while not FStop do begin
363 if context <> nil
364 then context.Processing( client);
365 if not FProcessor.Process( InputProtocol, OutputProtocol, context)
366 then Break;
Jake Farrell27274222011-11-10 20:32:44 +0000367 end;
Jens Geyer06045cf2013-03-27 20:26:25 +0200368
Jake Farrell27274222011-11-10 20:32:44 +0000369 except
370 on E: TTransportException do
371 begin
Roger Meier79655fb2012-10-20 20:59:41 +0000372 if FStop
373 then FLogDelegate('TSimpleServer was shutting down, caught ' + E.ToString)
374 else FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000375 end;
376 on E: Exception do
377 begin
Roger Meier79655fb2012-10-20 20:59:41 +0000378 FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000379 end;
380 end;
Jens Geyer01640402013-09-25 21:12:21 +0200381
382 if context <> nil
383 then begin
384 context.CleanupContext;
385 context := nil;
386 end;
387
Jake Farrell27274222011-11-10 20:32:44 +0000388 if InputTransport <> nil then
389 begin
390 InputTransport.Close;
391 end;
392 if OutputTransport <> nil then
393 begin
394 OutputTransport.Close;
395 end;
396 end;
397
398 if FStop then
399 begin
400 try
401 FServerTransport.Close;
402 except
403 on E: TTransportException do
404 begin
405 FLogDelegate('TServerTranport failed on close: ' + E.Message);
406 end;
407 end;
408 FStop := False;
409 end;
410end;
411
412procedure TSimpleServer.Stop;
413begin
414 FStop := True;
415 FServerTransport.Close;
416end;
417
418end.