blob: a73e6cb447508dd629a7121ca7e8e8db0529f40f [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 Geyer9f7f11e2016-04-14 21:37:11 +020022{$I Thrift.Defines.inc}
Jens Geyer26ef7432013-09-23 22:01:20 +020023{$I-} // prevent annoying errors with default log delegate and no console
24
Jake Farrell27274222011-11-10 20:32:44 +000025interface
26
27uses
Jens Geyer9f7f11e2016-04-14 21:37:11 +020028 {$IFDEF OLD_UNIT_NAMES}
29 Windows, SysUtils,
Nick4f5229e2016-04-14 16:43:22 +030030 {$ELSE}
Jens Geyer9f7f11e2016-04-14 21:37:11 +020031 Winapi.Windows, System.SysUtils,
32 {$ENDIF}
Jake Farrell27274222011-11-10 20:32:44 +000033 Thrift,
34 Thrift.Protocol,
Jens Geyera019cda2019-11-09 23:24:52 +010035 Thrift.Transport,
36 Thrift.Configuration;
Jake Farrell27274222011-11-10 20:32:44 +000037
38type
Jens Geyer01640402013-09-25 21:12:21 +020039 IServerEvents = interface
40 ['{9E2A99C5-EE85-40B2-9A52-2D1722B18176}']
41 // Called before the server begins.
42 procedure PreServe;
43 // Called when the server transport is ready to accept requests
44 procedure PreAccept;
45 // Called when a new client has connected and the server is about to being processing.
46 function CreateProcessingContext( const input, output : IProtocol) : IProcessorEvents;
47 end;
48
49
Jake Farrell27274222011-11-10 20:32:44 +000050 IServer = interface
Jens Geyer01640402013-09-25 21:12:21 +020051 ['{ADC46F2D-8199-4D1C-96D2-87FD54351723}']
Jake Farrell27274222011-11-10 20:32:44 +000052 procedure Serve;
53 procedure Stop;
Jens Geyer01640402013-09-25 21:12:21 +020054
55 function GetServerEvents : IServerEvents;
56 procedure SetServerEvents( const value : IServerEvents);
57
58 property ServerEvents : IServerEvents read GetServerEvents write SetServerEvents;
Jake Farrell27274222011-11-10 20:32:44 +000059 end;
60
61 TServerImpl = class abstract( TInterfacedObject, IServer )
62 public
63 type
Roger Meier333bbf32012-01-08 21:51:08 +000064 TLogDelegate = reference to procedure( const str: string);
Jens Geyered994552019-11-09 23:24:52 +010065 strict protected
Jake Farrell27274222011-11-10 20:32:44 +000066 FProcessor : IProcessor;
67 FServerTransport : IServerTransport;
68 FInputTransportFactory : ITransportFactory;
69 FOutputTransportFactory : ITransportFactory;
70 FInputProtocolFactory : IProtocolFactory;
71 FOutputProtocolFactory : IProtocolFactory;
72 FLogDelegate : TLogDelegate;
Jens Geyer01640402013-09-25 21:12:21 +020073 FServerEvents : IServerEvents;
Jens Geyera019cda2019-11-09 23:24:52 +010074 FConfiguration : IThriftConfiguration;
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(
Jens Geyerfad7fd32019-11-09 23:24:52 +010085 const aProcessor :IProcessor;
86 const aServerTransport: IServerTransport;
87 const aInputTransportFactory : ITransportFactory;
88 const aOutputTransportFactory : ITransportFactory;
89 const aInputProtocolFactory : IProtocolFactory;
90 const aOutputProtocolFactory : IProtocolFactory;
Jens Geyera019cda2019-11-09 23:24:52 +010091 const aConfig : IThriftConfiguration;
Jens Geyerfad7fd32019-11-09 23:24:52 +010092 const aLogDelegate : TLogDelegate
Jake Farrell27274222011-11-10 20:32:44 +000093 ); overload;
94
Jens Geyer01640402013-09-25 21:12:21 +020095 constructor Create(
Jens Geyera019cda2019-11-09 23:24:52 +010096 const aProcessor: IProcessor;
Jens Geyerfad7fd32019-11-09 23:24:52 +010097 const aServerTransport: IServerTransport;
Jens Geyera019cda2019-11-09 23:24:52 +010098 const aTransportFactory: ITransportFactory = nil;
99 const aProtocolFactory: IProtocolFactory = nil;
100 const aConfig : IThriftConfiguration = nil;
101 const aLogDel: TServerImpl.TLogDelegate = nil
Jake Farrell27274222011-11-10 20:32:44 +0000102 ); overload;
103 end;
104
Jens Geyerfad7fd32019-11-09 23:24:52 +0100105
Jake Farrell27274222011-11-10 20:32:44 +0000106 TSimpleServer = class( TServerImpl)
Jens Geyer2646bd62019-11-09 23:24:52 +0100107 private
Jake Farrell27274222011-11-10 20:32:44 +0000108 FStop : Boolean;
109 public
Jake Farrell27274222011-11-10 20:32:44 +0000110 procedure Serve; override;
111 procedure Stop; override;
112 end;
113
114
115implementation
116
117{ TServerImpl }
118
Jens Geyerfad7fd32019-11-09 23:24:52 +0100119constructor TServerImpl.Create( const aProcessor: IProcessor;
120 const aServerTransport: IServerTransport;
Jens Geyera019cda2019-11-09 23:24:52 +0100121 const aInputTransportFactory, aOutputTransportFactory: ITransportFactory;
122 const aInputProtocolFactory, aOutputProtocolFactory: IProtocolFactory;
123 const aConfig : IThriftConfiguration;
124 const aLogDelegate : TLogDelegate);
Jake Farrell27274222011-11-10 20:32:44 +0000125begin
Jens Geyer718f6ee2013-09-06 21:02:34 +0200126 inherited Create;
Jens Geyerfad7fd32019-11-09 23:24:52 +0100127 FProcessor := aProcessor;
128 FServerTransport := aServerTransport;
Jens Geyera019cda2019-11-09 23:24:52 +0100129
130 if aConfig <> nil
131 then FConfiguration := aConfig
132 else FConfiguration := TThriftConfigurationImpl.Create;
133
134 if aInputTransportFactory <> nil
135 then FInputTransportFactory := aInputTransportFactory
136 else FInputTransportFactory := TTransportFactoryImpl.Create;
137
138 if aOutputTransportFactory <> nil
139 then FOutputTransportFactory := aOutputTransportFactory
140 else FOutputTransportFactory := TTransportFactoryImpl.Create;
141
142 if aInputProtocolFactory <> nil
143 then FInputProtocolFactory := aInputProtocolFactory
144 else FInputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
145
146 if aOutputProtocolFactory <> nil
147 then FOutputProtocolFactory := aOutputProtocolFactory
148 else FOutputProtocolFactory := TBinaryProtocolImpl.TFactory.Create;
149
150 if Assigned(aLogDelegate)
151 then FLogDelegate := aLogDelegate
152 else FLogDelegate := DefaultLogDelegate;
Jake Farrell27274222011-11-10 20:32:44 +0000153end;
154
Jens Geyera019cda2019-11-09 23:24:52 +0100155
156constructor TServerImpl.Create( const aProcessor: IProcessor;
157 const aServerTransport: IServerTransport;
158 const aTransportFactory: ITransportFactory;
159 const aProtocolFactory: IProtocolFactory;
160 const aConfig : IThriftConfiguration;
161 const aLogDel: TServerImpl.TLogDelegate);
162begin
163 Create( aProcessor, aServerTransport,
164 aTransportFactory, aTransportFactory,
165 aProtocolFactory, aProtocolFactory,
166 aConfig, aLogDel);
167end;
168
169
Roger Meier333bbf32012-01-08 21:51:08 +0000170class procedure TServerImpl.DefaultLogDelegate( const str: string);
Jake Farrell27274222011-11-10 20:32:44 +0000171begin
Jens Geyer26ef7432013-09-23 22:01:20 +0200172 try
173 Writeln( str);
174 if IoResult <> 0 then OutputDebugString(PChar(str));
175 except
176 OutputDebugString(PChar(str));
177 end;
Jake Farrell27274222011-11-10 20:32:44 +0000178end;
179
Jake Farrell806d2982011-10-26 02:33:31 +0000180
Jens Geyer01640402013-09-25 21:12:21 +0200181
182function TServerImpl.GetServerEvents : IServerEvents;
183begin
184 result := FServerEvents;
185end;
186
187
188procedure TServerImpl.SetServerEvents( const value : IServerEvents);
189begin
190 // if you need more than one, provide a specialized IServerEvents implementation
191 FServerEvents := value;
192end;
193
194
Jake Farrell806d2982011-10-26 02:33:31 +0000195{ TSimpleServer }
Jake Farrell27274222011-11-10 20:32:44 +0000196
Jake Farrell27274222011-11-10 20:32:44 +0000197procedure TSimpleServer.Serve;
198var
199 client : ITransport;
200 InputTransport : ITransport;
201 OutputTransport : ITransport;
202 InputProtocol : IProtocol;
203 OutputProtocol : IProtocol;
Jens Geyer01640402013-09-25 21:12:21 +0200204 context : IProcessorEvents;
Jake Farrell27274222011-11-10 20:32:44 +0000205begin
206 try
207 FServerTransport.Listen;
208 except
209 on E: Exception do
210 begin
211 FLogDelegate( E.ToString);
212 end;
213 end;
214
Jens Geyer01640402013-09-25 21:12:21 +0200215 if FServerEvents <> nil
216 then FServerEvents.PreServe;
217
Jake Farrell27274222011-11-10 20:32:44 +0000218 client := nil;
Jake Farrell27274222011-11-10 20:32:44 +0000219 while (not FStop) do
220 begin
221 try
Jens Geyer06045cf2013-03-27 20:26:25 +0200222 // clean up any old instances before waiting for clients
223 InputTransport := nil;
224 OutputTransport := nil;
225 InputProtocol := nil;
226 OutputProtocol := nil;
227
Jens Geyer3e8d9272014-09-14 20:10:40 +0200228 // close any old connections before before waiting for new clients
229 if client <> nil then try
230 try
231 client.Close;
232 finally
233 client := nil;
234 end;
235 except
236 // catch all, we can't do much about it at this point
237 end;
238
Jens Geyer01640402013-09-25 21:12:21 +0200239 client := FServerTransport.Accept( procedure
240 begin
Jens Geyerd5436f52014-10-03 19:50:38 +0200241 if FServerEvents <> nil
Jens Geyer01640402013-09-25 21:12:21 +0200242 then FServerEvents.PreAccept;
Jens Geyerd5436f52014-10-03 19:50:38 +0200243 end);
244
245 if client = nil then begin
246 if FStop
247 then Abort // silent exception
Jens Geyere0e32402016-04-20 21:50:48 +0200248 else raise TTransportExceptionUnknown.Create('ServerTransport.Accept() may not return NULL');
Jens Geyerd5436f52014-10-03 19:50:38 +0200249 end;
250
Jake Farrell27274222011-11-10 20:32:44 +0000251 FLogDelegate( 'Client Connected!');
Jens Geyer06045cf2013-03-27 20:26:25 +0200252
Jake Farrell27274222011-11-10 20:32:44 +0000253 InputTransport := FInputTransportFactory.GetTransport( client );
254 OutputTransport := FOutputTransportFactory.GetTransport( client );
255 InputProtocol := FInputProtocolFactory.GetProtocol( InputTransport );
256 OutputProtocol := FOutputProtocolFactory.GetProtocol( OutputTransport );
Jens Geyer01640402013-09-25 21:12:21 +0200257
258 if FServerEvents <> nil
259 then context := FServerEvents.CreateProcessingContext( InputProtocol, OutputProtocol)
260 else context := nil;
261
262 while not FStop do begin
263 if context <> nil
264 then context.Processing( client);
265 if not FProcessor.Process( InputProtocol, OutputProtocol, context)
266 then Break;
Jake Farrell27274222011-11-10 20:32:44 +0000267 end;
Jens Geyer06045cf2013-03-27 20:26:25 +0200268
Jake Farrell27274222011-11-10 20:32:44 +0000269 except
Jens Geyerc140bb92019-11-27 22:18:12 +0100270 on E: TTransportException do begin
Roger Meier79655fb2012-10-20 20:59:41 +0000271 if FStop
272 then FLogDelegate('TSimpleServer was shutting down, caught ' + E.ToString)
273 else FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000274 end;
Jens Geyerc140bb92019-11-27 22:18:12 +0100275 on E: Exception do begin
Roger Meier79655fb2012-10-20 20:59:41 +0000276 FLogDelegate( E.ToString);
Jake Farrell27274222011-11-10 20:32:44 +0000277 end;
278 end;
Jens Geyer01640402013-09-25 21:12:21 +0200279
Jens Geyerc140bb92019-11-27 22:18:12 +0100280 if context <> nil then begin
Jens Geyer01640402013-09-25 21:12:21 +0200281 context.CleanupContext;
282 context := nil;
283 end;
284
Jake Farrell27274222011-11-10 20:32:44 +0000285 if InputTransport <> nil then
286 begin
287 InputTransport.Close;
288 end;
289 if OutputTransport <> nil then
290 begin
291 OutputTransport.Close;
292 end;
293 end;
294
295 if FStop then
296 begin
297 try
298 FServerTransport.Close;
299 except
300 on E: TTransportException do
301 begin
302 FLogDelegate('TServerTranport failed on close: ' + E.Message);
303 end;
304 end;
305 FStop := False;
306 end;
307end;
308
309procedure TSimpleServer.Stop;
310begin
311 FStop := True;
312 FServerTransport.Close;
313end;
314
315end.