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