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