This commit was generated by cvs2svn to compensate for changes in r12269,
[u/mrichter/AliRoot.git] / SHUTTLE / AliDCSClient.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /*
17 $Log$
18 Revision 1.1.1.1  2005/09/12 22:11:40  byordano
19 SHUTTLE package
20
21 Revision 1.3  2005/08/30 10:53:23  byordano
22 some more descriptions added
23
24 */
25
26 //
27 // This class represents the AliDCSClient.
28 // The client used for data retrieval from DCS server.
29 // There are two way for retrieving data from the server.
30 //      1) asking for DP (DataPoint) - usually changed frequently.
31 //      2) asking for Alias (Alias) - alias should be the same through whole
32 //              experimnet.
33 //              
34 // There are two type of read operations:
35 //      Asking for single alias/dp or asking for set of aliases/dp
36 //
37 // In case of ServerError the coresponding error code and 
38 // error string (description) could be got by GetServerErrorCode() and
39 // GetServerErrorString()
40 //
41
42 #include "AliDCSClient.h"
43
44 #include "AliDCSValue.h"
45 #include "AliLog.h"
46
47 #include <TList.h>
48 #include <TMap.h>
49 #include <TObjString.h>
50 #include <TSystem.h>
51
52 ClassImp(AliDCSClient)
53
54 const Int_t AliDCSClient::fgkBadState;
55
56 const Int_t AliDCSClient::fgkInvalidParameter;
57
58 const Int_t AliDCSClient::fgkTimeout;
59
60 const Int_t AliDCSClient::fgkBadMessage;
61
62 const Int_t AliDCSClient::fgkCommError;
63
64 const Int_t AliDCSClient::fgkServerError;
65
66 const char* AliDCSClient::fgkBadStateString = "BadState";
67
68 const char* AliDCSClient::fgkInvalidParameterString = "InvalidParameter";
69
70 const char* AliDCSClient::fgkTimeoutString = "Timeout";
71
72 const char* AliDCSClient::fgkBadMessageString = "BadMessage";
73
74 const char* AliDCSClient::fgkCommErrorString = "CommunicationError";
75
76 const char* AliDCSClient::fgkServerErrorString = "ServerError";
77
78 AliDCSClient::AliDCSClient(const char* host, Int_t port, UInt_t timeout,
79         Int_t retries):
80         fSocket(NULL), fTimeout(timeout), fRetries(retries),
81         fServerErrorCode(AliDCSMessage::kNoneError), fServerError("")
82 {
83         // 
84         // host: DCS server host
85         // port: DCS server port
86         // timeout: in case of communication error or socket read/write this 
87         //              timeout will be used before the next try is made. 
88         // retries: the number of retries after which the connection is 
89         //              is considered as invalid and error is returned.
90         //
91
92         Int_t tries = 0;        
93         
94         while (tries < fRetries) {
95                 fSocket = new TSocket(host, port);
96                 if (fSocket->IsValid()) {
97                         AliDebug(1, Form("Connected to %s:%d", host, port));
98                         fSocket->SetOption(kNoBlock, 1);
99                         break;
100                 }
101                 
102                 AliDebug(1, Form("Connection timeout! tries <%d> ...", tries));
103
104                 delete fSocket;
105                 fSocket = NULL;
106
107                 gSystem->Sleep(fTimeout);
108                 tries ++;
109         }
110 }
111
112 AliDCSClient::~AliDCSClient() {
113         if (fSocket) {
114                 Close();
115                 delete fSocket;
116         }
117 }
118
119 Int_t AliDCSClient::SendBuffer(const char* buffer, Int_t size) {
120
121         Int_t sentSize = 0;
122         Int_t tries = 0;
123
124         while (sentSize < size && tries < fRetries) {
125
126                 Int_t sResult = fSocket->Select(TSocket::kWrite, fTimeout);
127
128                 if (sResult == 0) {
129                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
130                         tries ++;
131                         continue;
132
133                 } else if (sResult < 0) {
134                         AliDebug(1, Form("Communication error <%d>!", 
135                                         fSocket->GetErrorCode()));
136                         return AliDCSClient::fgkCommError;
137                 }
138
139                 sResult = fSocket->SendRaw(buffer + sentSize, size - sentSize,
140                                         kDontBlock);
141
142                 if (sResult > 0) {
143                         sentSize += sResult;
144                 } else {
145                         AliDebug(1, Form("Communication error <%d>!",
146                                         fSocket->GetErrorCode()));
147                         return AliDCSClient::fgkCommError;
148                 }
149         }
150
151         if (tries == fRetries) {
152                 return AliDCSClient::fgkTimeout;
153         }
154
155         return sentSize;
156 }
157
158 Int_t AliDCSClient::ReceiveBuffer(char* buffer, Int_t size) {
159
160         Int_t receivedSize = 0;
161         Int_t tries = 0;
162
163         while (receivedSize < size && tries < fRetries) {
164
165                 Int_t sResult = fSocket->Select(TSocket::kRead, fTimeout);
166
167                 if (sResult == 0) {
168                         AliDebug(1, Form("Timeout! tries <%d> ...", tries));
169                         tries ++;
170                         continue;
171
172                 } else if (sResult < 0) {
173                         AliDebug(1, Form("Communication error <%d>",
174                                         fSocket->GetErrorCode()));
175                         return AliDCSClient::fgkCommError;
176                 }
177
178                 sResult = fSocket->RecvRaw(buffer + receivedSize, 
179                         size - receivedSize, kDontBlock);
180
181                 if (sResult > 0) {
182                         receivedSize += sResult;
183                 } else {
184                         AliDebug(1, Form("Communication error <%d>",
185                                         fSocket->GetErrorCode()));
186                         return AliDCSClient::fgkCommError;
187                 }
188         }
189
190         if (tries == fRetries) {
191                 return AliDCSClient::fgkTimeout;
192         }
193
194         return receivedSize;
195 }
196
197 Int_t AliDCSClient::SendMessage(AliDCSMessage& message) {
198
199         message.StoreToBuffer();
200
201         AliDebug(2, "Sending message.\n"); 
202         message.Print();
203
204         return SendBuffer(message.GetMessage(), message.GetMessageSize());
205 }
206
207 Int_t AliDCSClient::ReceiveMessage(AliDCSMessage& message) {
208         
209         char header[HEADER_SIZE];
210
211         Int_t sResult;
212
213         if ((sResult = ReceiveBuffer(header, HEADER_SIZE)) < 0) {
214                 AliDebug(1, Form("Can't receive message header! Reason: %s", 
215                         GetErrorString(sResult)));
216                 return sResult;
217         }
218
219         if (!message.SetRawHeader(header)) {
220                 return AliDCSClient::fgkBadMessage;
221         }
222
223         if ((sResult = ReceiveBuffer(message.GetBody(), 
224                         message.GetBodySize())) < 0) {
225                 
226                 AliDebug(1, Form("Can't receive message body! Reason: %s", 
227                         GetErrorString(sResult)));
228                 return sResult;
229         }
230
231         message.LoadFromBuffer();
232
233         AliDebug(2, "Message received.");
234         message.Print();
235
236         return HEADER_SIZE + sResult;
237 }
238
239 Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
240         const char* reqString, UInt_t startTime, UInt_t endTime, TList& result) 
241 {
242         if (!IsConnected()) {
243                 AliError("Not connected!");
244                 return AliDCSClient::fgkBadState;
245         }
246
247         Int_t sResult;
248         AliDCSMessage requestMessage;
249         requestMessage.CreateRequestMessage(reqType, startTime, endTime, 
250                         reqString);
251
252         if ((sResult = SendMessage(requestMessage)) < 0) {
253                 AliError(Form("Can't send request message! Reason: %s",
254                         GetErrorString(sResult)));
255                 Close();
256                 return sResult;
257         }       
258         
259         sResult = ReceiveValueSet(result);
260         
261         Close();
262
263         return sResult;
264 }
265
266 Int_t AliDCSClient::GetValues(AliDCSMessage::RequestType reqType,
267         UInt_t startTime, UInt_t endTime, TMap& result) 
268 {
269         if (!IsConnected()) {
270                 AliError("Not connected!");
271                 return AliDCSClient::fgkBadState;
272         }       
273
274         AliDCSMessage multiRequestMessage;
275         multiRequestMessage.CreateMultiRequestMessage(reqType, 
276                         startTime, endTime);
277
278         TList requests;
279         
280         TIter iter(&result);
281         TObjString* aRequest;
282         
283         // copy request strings to temporary TList because
284         // TMap doesn't guarantee the order of elements!!!
285         while ((aRequest = (TObjString*) iter.Next())) {
286                 requests.Add(aRequest);
287                 if (!multiRequestMessage.AddRequestString(aRequest->String()))
288                 {
289                         return AliDCSClient::fgkInvalidParameter;
290                 }
291         }
292
293         Int_t sResult;
294         if ((sResult = SendMessage(multiRequestMessage)) < 0) {
295                 AliError(Form("Can't send request message! Reason: %s",
296                         GetErrorString(sResult)));
297                 Close();
298                 return sResult;
299         }
300
301         result.SetOwner(0);
302         result.Clear();
303
304         TIter reqIter(&requests);
305         while ((aRequest = (TObjString*) reqIter.Next())) {
306                 TList* resultSet = new TList();
307                 resultSet->SetOwner(1);
308
309                 if ((sResult = ReceiveValueSet(*resultSet)) < 0) {
310                         AliError(Form("Can't get values for %s!" ,
311                                 aRequest->String().Data()));
312
313                         delete resultSet;
314                         break;
315                 }
316
317                 result.Add(aRequest, resultSet);
318         }
319
320         if (sResult < 0) {
321                 result.DeleteValues();
322                 result.Clear();
323
324                 requests.Delete();
325         } else {
326                 result.SetOwner(1);
327         }
328
329         Close();
330
331         return sResult;
332 }
333         
334 Int_t AliDCSClient::ReceiveValueSet(TList& result) {
335
336         Int_t sResult;
337
338         AliDCSMessage responseMessage;
339         if ((sResult = ReceiveMessage(responseMessage)) < 0) {
340                 AliError(Form("Can't receive response message! Reason: %s",
341                         GetErrorString(sResult)));
342                 return sResult;
343         }       
344
345         UInt_t valueCount;
346
347         if (responseMessage.GetType() == AliDCSMessage::kCount) {
348                 valueCount = responseMessage.GetCount();
349
350         } else if (responseMessage.GetType() == AliDCSMessage::kError) {
351                 fServerErrorCode = responseMessage.GetErrorCode();
352                 fServerError = responseMessage.GetErrorString();
353
354                 return AliDCSClient::fgkServerError;
355
356         } else {
357                 AliError("Bad message type received!"); 
358                 return AliDCSClient::fgkBadMessage;
359         }
360
361         UInt_t receivedValues = 0;
362
363         AliSimpleValue::Type valueType = AliSimpleValue::kInvalid;
364
365         while (receivedValues < valueCount) {
366
367                 AliDCSMessage message;
368
369                 if ((sResult = ReceiveMessage(message)) < 0) {
370                         AliError(Form("Can't receive message! Reason: %s",
371                                 GetErrorString(sResult)));
372                         return sResult;
373                 }
374
375                 if (message.GetType() == AliDCSMessage::kResultSet) {
376
377                         if (valueType == AliSimpleValue::kInvalid) {
378                                 valueType = message.GetSimpleValueType();
379                         } else {
380                                 if (valueType != message.GetSimpleValueType()) {
381                                         AliError("Unexpected value type!");
382                                         return AliDCSClient::fgkBadMessage;
383                                 }
384                         }
385                         
386                         receivedValues += message.GetValues(result);
387
388                         if (receivedValues > valueCount) {
389                                 AliError("Message contains more values than expected!");
390                                 return AliDCSClient::fgkBadMessage;
391                         }
392
393                 } else if (message.GetType() == AliDCSMessage::kError) {
394                                 fServerErrorCode = 
395                                         responseMessage.GetErrorCode();
396                                 fServerError = responseMessage.GetErrorString();
397
398                                 return AliDCSClient::fgkServerError;
399                 } else {
400                         AliError("Bad message type received!");
401                         return AliDCSClient::fgkBadMessage;
402                 }       
403         }       
404         
405         return receivedValues;
406 }
407                 
408 Int_t AliDCSClient::GetDPValues(const char* dpName, UInt_t startTime,
409                                 UInt_t endTime, TList& result)
410 {
411         //
412         // Reads a values from the server which correspond to this
413         // DataPoint (dpName) in time interval (startTime - endTime).
414         // result: Collection of AliDCSValue which contains the read values.
415         //
416         // Returns:
417         //      If >= 0 , the number of values read.
418         //      if < 0, the error code which has occured during the read.
419         //
420
421         return GetValues(AliDCSMessage::kDPName, 
422                         dpName, startTime, endTime, result);
423 }
424
425 Int_t AliDCSClient::GetAliasValues(const char* alias, UInt_t startTime,
426                                 UInt_t endTime, TList& result)
427 {
428         //
429         // Reads a values from the server which correspond to this
430         // alias (alias) in time interval (startTime - endTime).
431         // result: Collection of AliDCSValue which contains the read values.
432         //
433         // Returns:
434         //      If >= 0 , the number of values read.
435         //      if < 0, the error code which has occured during the read.
436         //
437
438         return GetValues(AliDCSMessage::kAlias, 
439                         alias, startTime, endTime, result);
440 }
441
442 Int_t AliDCSClient::GetDPValues(UInt_t startTime, UInt_t endTime, 
443                                 TMap& result) 
444 {
445         //
446         // For every key of 'result' (which must be TObjString) 
447         // reads a valueSet. The key represents particular DataPoint to be read.
448         // For all DataPoints time interval (startTime - endTime) is used.
449         // After the read, the correspoding value for every key is a 
450         // TList - collection of AliDCSValue, or result is an empty map in
451         // case of error.
452         // 
453         // Returns:
454         //      If >= 0 , the number of values read.
455         //      if < 0, the error code which has occured during the read.
456         //
457
458         return GetValues(AliDCSMessage::kDPName, startTime, endTime, result);
459 }
460
461 Int_t AliDCSClient::GetAliasValues(UInt_t startTime, UInt_t endTime,
462                                 TMap& result) 
463 {
464         //
465         // For every key of 'result' (which must be TObjString) 
466         // reads a valueSet. The key represents particular Alias to be read.
467         // For all aliases time interval (startTime - endTime) is used.
468         // After the read, the correspoding value for every key is a 
469         // TList - collection of AliDCSValue, or result is an empty map in
470         // case of error.
471         // 
472         // Returns:
473         //      If >= 0 , the number of values read.
474         //      if < 0, the error code which has occured during the read.
475         //
476
477         return GetValues(AliDCSMessage::kAlias, startTime, endTime, result);
478 }
479
480 Bool_t AliDCSClient::IsConnected() {
481         //
482         // Returns kTRUE if there is a valid connection to the server.
483         //
484
485         if (fSocket) {
486                 return fSocket->IsValid();
487         }
488
489         return kFALSE;
490 }
491
492 void AliDCSClient::Close() {
493         //
494         // Close the connection.
495         //
496
497         if (fSocket) {
498                 fSocket->Close();
499         }
500 }
501
502 const char* AliDCSClient::GetErrorString(Int_t code) {
503         //
504         // Returns a short string describing the error code.
505         // code: the error code.
506         //
507         
508
509         switch (code) {
510                 case AliDCSClient::fgkBadState:
511                         return AliDCSClient::fgkBadStateString;
512
513                 case AliDCSClient::fgkInvalidParameter:
514                         return AliDCSClient::fgkInvalidParameterString;
515
516                 case AliDCSClient::fgkTimeout:
517                         return AliDCSClient::fgkTimeoutString;
518
519                 case AliDCSClient::fgkBadMessage:
520                         return AliDCSClient::fgkBadMessageString;
521         
522                 case AliDCSClient::fgkCommError:
523                         return AliDCSClient::fgkCommErrorString;
524
525                 case AliDCSClient::fgkServerError:
526                         return AliDCSClient::fgkServerErrorString;
527
528                 default:
529                         AliErrorGeneral("AliDCSClient::GetErrorString",
530                                 "Unknown error code!");
531                         return "UnknownCode";
532         }
533 }
534