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