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