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