blob: 8d95ed24f50a2b48094fc3e16f6218e658bdd6ed [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
Nick4f5229e2016-04-14 16:43:22 +030023{$IF CompilerVersion >= 23.0}
24 {$LEGACYIFEND ON}
25{$IFEND}
Jens Geyer26ef7432013-09-23 22:01:20 +020026
Jake Farrell27274222011-11-10 20:32:44 +000027interface
28
29uses
Nick4f5229e2016-04-14 16:43:22 +030030 {$IF CompilerVersion < 23.0}
31 Windows, SysUtils,
32 {$ELSE}
33 Winapi.Windows, System.SysUtils,
34 {$IFEND}
Jake Farrell27274222011-11-10 20:32:44 +000035 Thrift,
36 Thrift.Protocol,
37 Thrift.Transport;
38
39type
Jens Geyer01640402013-09-25 21:12:21 +020040 IServerEvents = interface
41 ['{9E2A99C5-EE85-40B2-9A52-2D1722B18176}']
42 // Called before the server begins.
43 procedure PreServe;
44 // Called when the server transport is ready to accept requests
45 procedure PreAccept;
46 // Called when a new client has connected and the server is about to being processing.
47 function CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
48 end;
49
50
Jake Farrell27274222011-11-10 20:32:44 +000051 IServer = interface
Jens Geyer01640402013-09-25 21:12:21 +020052 ['{ADC46F2D-8199-4D1C-96D2-87FD54351723}']
Jake Farrell27274222011-11-10 20:32:44 +000053 procedure Serve;
54 procedure Stop;
Jens Geyer01640402013-09-25 21:12:21 +020055
56 function GetServerEvents : IServerEvents;
57 procedure SetServerEvents( const value : IServerEvents);
58
59 property ServerEvents : IServerEvents read GetServerEvents write SetServerEvents;
Jake Farrell27274222011-11-10 20:32:44 +000060 end;
61
62 TServerImpl = class abstract( TInterfacedObject, IServer )
63 public
64 type
Roger Meier333bbf32012-01-08 21:51:08 +000065 TLogDelegate = reference to procedure( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +000066 protected
67 FProcessor : IProcessor;
68 FServerTransport : IServerTransport;
69 FInputTransportFactory : ITransportFactory;
70 FOutputTransportFactory : ITransportFactory;
71 FInputProtocolFactory : IProtocolFactory;
72 FOutputProtocolFactory : IProtocolFactory;
73 FLogDelegate : TLogDelegate;
Jens Geyer01640402013-09-25 21:12:21 +020074 FServerEvents : IServerEvents;
Jake Farrell27274222011-11-10 20:32:44 +000075
Roger Meier333bbf32012-01-08 21:51:08 +000076 class procedure DefaultLogDelegate( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +000077
Jens Geyer01640402013-09-25 21:12:21 +020078 function GetServerEvents : IServerEvents;
79 procedure SetServerEvents( const value : IServerEvents);
80
Jake Farrell27274222011-11-10 20:32:44 +000081 procedure Serve; virtual; abstract;
82 procedure Stop; virtual; abstract;
83 public
84 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000085 const AProcessor :IProcessor;
86 const AServerTransport: IServerTransport;
87 const AInputTransportFactory : ITransportFactory;
88 const AOutputTransportFactory : ITransportFactory;
89 const AInputProtocolFactory : IProtocolFactory;
90 const AOutputProtocolFactory : IProtocolFactory;
91 const ALogDelegate : TLogDelegate
Jake Farrell27274222011-11-10 20:32:44 +000092 ); overload;
93
Jens Geyer01640402013-09-25 21:12:21 +020094 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +000095 const AProcessor :IProcessor;
96 const AServerTransport: IServerTransport
Jens Geyerd5436f52014-10-03 19:50:38 +020097 ); overload;
Jake Farrell27274222011-11-10 20:32:44 +000098
99 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +0000100 const AProcessor :IProcessor;
101 const AServerTransport: IServerTransport;
102 const ALogDelegate: TLogDelegate
Jake Farrell27274222011-11-10 20:32:44 +0000103 ); overload;
104
105 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +0000106 const AProcessor :IProcessor;
107 const AServerTransport: IServerTransport;
108 const ATransportFactory : ITransportFactory
Jake Farrell27274222011-11-10 20:32:44 +0000109 ); overload;
110
111 constructor Create(
Roger Meier333bbf32012-01-08 21:51:08 +0000112 const AProcessor :IProcessor;
113 const AServerTransport: IServerTransport;
114 const ATransportFactory : ITransportFactory;
115 const AProtocolFactory : IProtocolFactory
Jake Farrell27274222011-11-10 20:32:44 +0000116 ); overload;
117 end;
118
119 TSimpleServer = class( TServerImpl)
120 private
121 FStop : Boolean;
122 public
Roger Meier333bbf32012-01-08 21:51:08 +0000123 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport); overload;
124 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
Jake Farrell27274222011-11-10 20:32:44 +0000125 ALogDel: TServerImpl.TLogDelegate); overload;
Roger Meier333bbf32012-01-08 21:51:08 +0000126 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
127 const ATransportFactory: ITransportFactory); overload;
128 constructor Create( const AProcessor: IProcessor; const AServerTransport: IServerTransport;
129 const ATransportFactory: ITransportFactory; const AProtocolFactory: IProtocolFactory); overload;
Jake Farrell27274222011-11-10 20:32:44 +0000130
131 procedure Serve; override;
132 procedure Stop; override;
133 end;
134
135
136implementation
137
138{ TServerImpl }
139
Roger Meier333bbf32012-01-08 21:51:08 +0000140constructor TServerImpl.Create( const AProcessor: IProcessor;
141 const AServerTransport: IServerTransport; const ALogDelegate: TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000142var
143 InputFactory, OutputFactory : IProtocolFactory;
144 InputTransFactory, OutputTransFactory : ITransportFactory;
145
146begin
147 InputFactory := TBinaryProtocolImpl.TFactory.Create;
148 OutputFactory := TBinaryProtocolImpl.TFactory.Create;
149 InputTransFactory := TTransportFactoryImpl.Create;
150 OutputTransFactory := TTransportFactoryImpl.Create;
151
Jens Geyer01640402013-09-25 21:12:21 +0200152 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000153 Create(
154 AProcessor,
155 AServerTransport,
156 InputTransFactory,
157 OutputTransFactory,
158 InputFactory,
159 OutputFactory,
160 ALogDelegate
161 );
162end;
163
Roger Meier333bbf32012-01-08 21:51:08 +0000164constructor TServerImpl.Create(const AProcessor: IProcessor;
165 const AServerTransport: IServerTransport);
Jake Farrell27274222011-11-10 20:32:44 +0000166var
167 InputFactory, OutputFactory : IProtocolFactory;
168 InputTransFactory, OutputTransFactory : ITransportFactory;
169
170begin
171 InputFactory := TBinaryProtocolImpl.TFactory.Create;
172 OutputFactory := TBinaryProtocolImpl.TFactory.Create;
173 InputTransFactory := TTransportFactoryImpl.Create;
174 OutputTransFactory := TTransportFactoryImpl.Create;
175
Jens Geyerd5436f52014-10-03 19:50:38 +0200176 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000177 Create(
178 AProcessor,
179 AServerTransport,
180 InputTransFactory,
181 OutputTransFactory,
182 InputFactory,
183 OutputFactory,
184 DefaultLogDelegate
185 );
186end;
187
Roger Meier333bbf32012-01-08 21:51:08 +0000188constructor TServerImpl.Create(const AProcessor: IProcessor;
189 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000190var
191 InputProtocolFactory : IProtocolFactory;
192 OutputProtocolFactory : IProtocolFactory;
193begin
194 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
195 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
196
Jens Geyerd5436f52014-10-03 19:50:38 +0200197 //no inherited;
Jake Farrell27274222011-11-10 20:32:44 +0000198 Create( AProcessor, AServerTransport, ATransportFactory, ATransportFactory,
199 InputProtocolFactory, OutputProtocolFactory, DefaultLogDelegate);
200end;
201
Roger Meier333bbf32012-01-08 21:51:08 +0000202constructor TServerImpl.Create(const AProcessor: IProcessor;
203 const AServerTransport: IServerTransport;
204 const AInputTransportFactory, AOutputTransportFactory: ITransportFactory;
205 const AInputProtocolFactory, AOutputProtocolFactory: IProtocolFactory;
206 const ALogDelegate : TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000207begin
Jens Geyer718f6ee2013-09-06 21:02:34 +0200208 inherited Create;
Jake Farrell27274222011-11-10 20:32:44 +0000209 FProcessor := AProcessor;
210 FServerTransport := AServerTransport;
211 FInputTransportFactory := AInputTransportFactory;
212 FOutputTransportFactory := AOutputTransportFactory;
213 FInputProtocolFactory := AInputProtocolFactory;
214 FOutputProtocolFactory := AOutputProtocolFactory;
215 FLogDelegate := ALogDelegate;
216end;
217
Roger Meier333bbf32012-01-08 21:51:08 +0000218class procedure TServerImpl.DefaultLogDelegate( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +0000219begin
Jens Geyer26ef7432013-09-23 22:01:20 +0200220 try
221 Writeln( str);
222 if IoResult <> 0 then OutputDebugString(PChar(str));
223 except
224 OutputDebugString(PChar(str));
225 end;
Jake Farrell27274222011-11-10 20:32:44 +0000226end;
227
Roger Meier333bbf32012-01-08 21:51:08 +0000228constructor TServerImpl.Create( const AProcessor: IProcessor;
229 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
230 const AProtocolFactory: IProtocolFactory);
Jake Farrell806d2982011-10-26 02:33:31 +0000231begin
Jens Geyer01640402013-09-25 21:12:21 +0200232 //no inherited;
Jake Farrell806d2982011-10-26 02:33:31 +0000233 Create( AProcessor, AServerTransport,
234 ATransportFactory, ATransportFactory,
235 AProtocolFactory, AProtocolFactory,
236 DefaultLogDelegate);
237end;
238
Jens Geyer01640402013-09-25 21:12:21 +0200239
240function TServerImpl.GetServerEvents : IServerEvents;
241begin
242 result := FServerEvents;
243end;
244
245
246procedure TServerImpl.SetServerEvents( const value : IServerEvents);
247begin
248 // if you need more than one, provide a specialized IServerEvents implementation
249 FServerEvents := value;
250end;
251
252
Jake Farrell806d2982011-10-26 02:33:31 +0000253{ TSimpleServer }
Jake Farrell27274222011-11-10 20:32:44 +0000254
Roger Meier333bbf32012-01-08 21:51:08 +0000255constructor TSimpleServer.Create( const AProcessor: IProcessor;
256 const AServerTransport: IServerTransport);
Jake Farrell27274222011-11-10 20:32:44 +0000257var
258 InputProtocolFactory : IProtocolFactory;
259 OutputProtocolFactory : IProtocolFactory;
260 InputTransportFactory : ITransportFactory;
261 OutputTransportFactory : ITransportFactory;
262begin
263 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
264 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
265 InputTransportFactory := TTransportFactoryImpl.Create;
266 OutputTransportFactory := TTransportFactoryImpl.Create;
267
268 inherited Create( AProcessor, AServerTransport, InputTransportFactory,
269 OutputTransportFactory, InputProtocolFactory, OutputProtocolFactory, DefaultLogDelegate);
270end;
271
Roger Meier333bbf32012-01-08 21:51:08 +0000272constructor TSimpleServer.Create( const AProcessor: IProcessor;
273 const AServerTransport: IServerTransport; ALogDel: TServerImpl.TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000274var
275 InputProtocolFactory : IProtocolFactory;
276 OutputProtocolFactory : IProtocolFactory;
277 InputTransportFactory : ITransportFactory;
278 OutputTransportFactory : ITransportFactory;
279begin
280 InputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
281 OutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
282 InputTransportFactory := TTransportFactoryImpl.Create;
283 OutputTransportFactory := TTransportFactoryImpl.Create;
284
285 inherited Create( AProcessor, AServerTransport, InputTransportFactory,
286 OutputTransportFactory, InputProtocolFactory, OutputProtocolFactory, ALogDel);
287end;
288
Roger Meier333bbf32012-01-08 21:51:08 +0000289constructor TSimpleServer.Create( const AProcessor: IProcessor;
290 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000291begin
292 inherited Create( AProcessor, AServerTransport, ATransportFactory,
293 ATransportFactory, TBinaryProtocolImpl.TFactory.Create, TBinaryProtocolImpl.TFactory.Create, DefaultLogDelegate);
294end;
295
Roger Meier333bbf32012-01-08 21:51:08 +0000296constructor TSimpleServer.Create( const AProcessor: IProcessor;
297 const AServerTransport: IServerTransport; const ATransportFactory: ITransportFactory;
298 const AProtocolFactory: IProtocolFactory);
Jake Farrell27274222011-11-10 20:32:44 +0000299begin
300 inherited Create( AProcessor, AServerTransport, ATransportFactory,
301 ATransportFactory, AProtocolFactory, AProtocolFactory, DefaultLogDelegate);
302end;
303
304procedure TSimpleServer.Serve;
305var
306 client : ITransport;
307 InputTransport : ITransport;
308 OutputTransport : ITransport;
309 InputProtocol : IProtocol;
310 OutputProtocol : IProtocol;
Jens Geyer01640402013-09-25 21:12:21 +0200311 context : IProcessorEvents;
Jake Farrell27274222011-11-10 20:32:44 +0000312begin
313 try
314 FServerTransport.Listen;
315 except
316 on E: Exception do
317 begin
318 FLogDelegate( E.ToString);
319 end;
320 end;
321
Jens Geyer01640402013-09-25 21:12:21 +0200322 if FServerEvents <> nil
323 then FServerEvents.PreServe;
324
Jake Farrell27274222011-11-10 20:32:44 +0000325 client := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000326 while (not FStop) do
327 begin
328 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200329 // clean up any old instances before waiting for clients
330 InputTransport := nil;
331 OutputTransport := nil;
332 InputProtocol := nil;
333 OutputProtocol := nil;
334
Jens Geyer3e8d9272014-09-14 20:10:40 +0200335 // close any old connections before before waiting for new clients
336 if client <> nil then try
337 try
338 client.Close;
339 finally
340 client := nil;
341 end;
342 except
343 // catch all, we can't do much about it at this point
344 end;
345
Jens Geyer01640402013-09-25 21:12:21 +0200346 client := FServerTransport.Accept( procedure
347 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200348 if FServerEvents <> nil
Jens Geyer01640402013-09-25 21:12:21 +0200349 then FServerEvents.PreAccept;
Jens Geyerd5436f52014-10-03 19:50:38 +0200350 end);
351
352 if client = nil then begin
353 if FStop
354 then Abort // silent exception
355 else raise TTransportException.Create( 'ServerTransport.Accept() may not return NULL' );
356 end;
357
Jake Farrell27274222011-11-10 20:32:44 +0000358 FLogDelegate( 'Client Connected!');
Jens Geyer06045cf2013-03-27 20:26:25 +0200359
Jake Farrell27274222011-11-10 20:32:44 +0000360 InputTransport := FInputTransportFactory.GetTransport( client );
361 OutputTransport := FOutputTransportFactory.GetTransport( client );
362 InputProtocol := FInputProtocolFactory.GetProtocol( InputTransport );
363 OutputProtocol := FOutputProtocolFactory.GetProtocol( OutputTransport );
Jens Geyer01640402013-09-25 21:12:21 +0200364
365 if FServerEvents <> nil
366 then context := FServerEvents.CreateProcessingContext( InputProtocol, OutputProtocol)
367 else context := nil;
368
369 while not FStop do begin
370 if context <> nil
371 then context.Processing( client);
372 if not FProcessor.Process( InputProtocol, OutputProtocol, context)
373 then Break;
Jake Farrell27274222011-11-10 20:32:44 +0000374 end;
Jens Geyer06045cf2013-03-27 20:26:25 +0200375
Jake Farrell27274222011-11-10 20:32:44 +0000376 except
377 on E: TTransportException do
378 begin
Roger Meier79655fb2012-10-20 20:59:41 +0000379 if FStop
380 then FLogDelegate('TSimpleServer was shutting down, caught ' + E.ToString)
381 else FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000382 end;
383 on E: Exception do
384 begin
Roger Meier79655fb2012-10-20 20:59:41 +0000385 FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000386 end;
387 end;
Jens Geyer01640402013-09-25 21:12:21 +0200388
389 if context <> nil
390 then begin
391 context.CleanupContext;
392 context := nil;
393 end;
394
Jake Farrell27274222011-11-10 20:32:44 +0000395 if InputTransport <> nil then
396 begin
397 InputTransport.Close;
398 end;
399 if OutputTransport <> nil then
400 begin
401 OutputTransport.Close;
402 end;
403 end;
404
405 if FStop then
406 begin
407 try
408 FServerTransport.Close;
409 except
410 on E: TTransportException do
411 begin
412 FLogDelegate('TServerTranport failed on close: ' + E.Message);
413 end;
414 end;
415 FStop := False;
416 end;
417end;
418
419procedure TSimpleServer.Stop;
420begin
421 FStop := True;
422 FServerTransport.Close;
423end;
424
425end.