1 karl 1.40 //%2006////////////////////////////////////////////////////////////////////////
|
2 mike 1.2 //
|
3 karl 1.30 // Copyright (c) 2000, 2001, 2002 BMC Software; Hewlett-Packard Development
4 // Company, L.P.; IBM Corp.; The Open Group; Tivoli Systems.
5 // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L.P.;
|
6 karl 1.20 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.30 // Copyright (c) 2004 BMC Software; Hewlett-Packard Development Company, L.P.;
8 // IBM Corp.; EMC Corporation; VERITAS Software Corporation; The Open Group.
|
9 karl 1.32 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 karl 1.40 // Copyright (c) 2006 Hewlett-Packard Development Company, L.P.; IBM Corp.;
12 // EMC Corporation; Symantec Corporation; The Open Group.
|
13 mike 1.2 //
14 // Permission is hereby granted, free of charge, to any person obtaining a copy
15 // of this software and associated documentation files (the "Software"), to
16 // deal in the Software without restriction, including without limitation the
17 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
18 // sell copies of the Software, and to permit persons to whom the Software is
19 // furnished to do so, subject to the following conditions:
|
20 kumpf 1.10 //
|
21 mike 1.2 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
22 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
23 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
24 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
25 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30 //==============================================================================
31 //
32 // Author: Mike Brasher (mbrasher@bmc.com)
33 //
34 // Modified By: Nitin Upasani, Hewlett-Packard Company (Nitin_Upasani@hp.com)
35 // Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com)
|
36 kumpf 1.13 // Carol Ann Krug Graves, Hewlett-Packard Company
37 // (carolann_graves@hp.com)
|
38 kumpf 1.14 // Yi Zhou, Hewlett-Packard Company (yi_zhou@hp.com)
|
39 dj.gorey 1.24 // Dan Gorey (djgorey@us.ibm.com)
|
40 se.gupta 1.27 // Seema Gupta (gseema@in.ibm.com) for PEP135
|
41 kumpf 1.31 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
42 joyce.j 1.33 // Josephine Eskaline Joyce, IBM (jojustin@in.ibm.com) for PEP#101
|
43 j.alex 1.37 // John Alex, IBM (johnalex@us.ibm.com) - Bug#2290
|
44 dj.gorey 1.24 //
|
45 mike 1.2 //%/////////////////////////////////////////////////////////////////////////////
46
47 #include <Pegasus/Common/Config.h>
|
48 kumpf 1.7 #include <Pegasus/Common/Constants.h>
|
49 mike 1.2 #include <Pegasus/Common/HTTPConnection.h>
50 #include <Pegasus/Common/XmlWriter.h>
51 #include <Pegasus/Common/TimeValue.h>
52 #include <Pegasus/Common/Exception.h>
|
53 kumpf 1.8 #include <Pegasus/Common/PegasusVersion.h>
54
|
55 mike 1.2 #include "CIMExportRequestEncoder.h"
56 #include "CIMExportResponseDecoder.h"
57 #include "CIMExportClient.h"
58
|
59 humberto 1.18 // l10n
60 #include <Pegasus/Common/MessageLoader.h>
61
|
62 mike 1.2 #include <iostream>
63
64 PEGASUS_USING_STD;
65
66 PEGASUS_NAMESPACE_BEGIN
67
68 CIMExportClient::CIMExportClient(
|
69 mday 1.4 Monitor* monitor,
70 HTTPConnector* httpConnector,
|
71 kumpf 1.12 Uint32 timeoutMilliseconds)
|
72 mday 1.4 :
|
73 kumpf 1.14 MessageQueue(PEGASUS_QUEUENAME_EXPORTCLIENT),
74 _monitor(monitor),
|
75 mday 1.3 _httpConnector(httpConnector),
|
76 kumpf 1.14 _httpConnection(0),
|
77 kumpf 1.12 _timeoutMilliseconds(timeoutMilliseconds),
|
78 mday 1.3 _connected(false),
79 _responseDecoder(0),
80 _requestEncoder(0)
|
81 mike 1.2 {
|
82 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::CIMExportClient()");
83 PEG_METHOD_EXIT();
|
84 mike 1.2 }
85
86 CIMExportClient::~CIMExportClient()
87 {
|
88 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::~CIMExportClient()");
|
89 konrad.r 1.15
|
90 kumpf 1.26 disconnect();
91
92 PEG_METHOD_EXIT();
|
93 mike 1.2 }
94
|
95 kumpf 1.14 void CIMExportClient::_connect()
|
96 mday 1.4 {
|
97 kumpf 1.34 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_connect()");
|
98 kumpf 1.26
|
99 kumpf 1.34 // Create response decoder:
|
100 mike 1.2
|
101 kumpf 1.34 _responseDecoder = new CIMExportResponseDecoder(
102 this, _requestEncoder, &_authenticator);
|
103 mike 1.2
|
104 kumpf 1.34 // Attempt to establish a connection:
|
105 mike 1.2
|
106 kumpf 1.34 try
107 {
108 _httpConnection = _httpConnector->connect(_connectHost,
109 _connectPortNumber,
110 _connectSSLContext.get(),
111 _responseDecoder);
112 }
113 catch (...)
114 {
115 // Some possible exceptions are CannotCreateSocketException,
116 // CannotConnectException, and InvalidLocatorException
|
117 kumpf 1.14 delete _responseDecoder;
|
118 kumpf 1.26 PEG_METHOD_EXIT();
|
119 kumpf 1.34 throw;
120 }
|
121 mike 1.2
|
122 kumpf 1.34 // Create request encoder:
|
123 mike 1.2
|
124 kumpf 1.34 String connectHost = _connectHost;
125 if (connectHost.size())
126 {
127 char portStr[32];
128 sprintf(portStr, ":%u", _connectPortNumber);
129 connectHost.append(portStr);
130 }
|
131 kumpf 1.29
|
132 kumpf 1.34 _requestEncoder = new CIMExportRequestEncoder(
133 _httpConnection, connectHost, &_authenticator);
|
134 mike 1.2
|
135 kumpf 1.34 _responseDecoder->setEncoderQueue(_requestEncoder);
|
136 mike 1.2
|
137 kumpf 1.34 _connected = true;
|
138 kumpf 1.26
|
139 marek 1.42 _httpConnection->setSocketWriteTimeout(_timeoutMilliseconds/1000+1);
140
|
141 kumpf 1.34 PEG_METHOD_EXIT();
|
142 mike 1.2 }
143
|
144 kumpf 1.23 void CIMExportClient::_disconnect()
145 {
|
146 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_disconnect()");
147
|
148 kumpf 1.23 if (_connected)
149 {
150 //
151 // destroy response decoder
152 //
|
153 kumpf 1.41 delete _responseDecoder;
154 _responseDecoder = 0;
|
155 kumpf 1.23
156 //
157 // Close the connection
158 //
159 if (_httpConnector)
160 {
161 _httpConnector->disconnect(_httpConnection);
162 _httpConnection = 0;
163 }
|
164 dj.gorey 1.24
|
165 kumpf 1.23
166 //
167 // destroy request encoder
168 //
|
169 kumpf 1.41 delete _requestEncoder;
170 _requestEncoder = 0;
|
171 kumpf 1.23
172 _connected = false;
173 }
|
174 kumpf 1.26 PEG_METHOD_EXIT();
|
175 kumpf 1.23 }
176
|
177 kumpf 1.14 void CIMExportClient::_reconnect()
178 {
|
179 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_reconnect()");
|
180 kumpf 1.23 _disconnect();
181 _authenticator.setRequestMessage(0);
|
182 kumpf 1.14 _connect();
|
183 kumpf 1.26 PEG_METHOD_EXIT();
|
184 kumpf 1.14 }
185
186 void CIMExportClient::connect(
187 const String& host,
188 const Uint32 portNumber)
189 {
|
190 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::connect()");
|
191 kumpf 1.14 // If already connected, bail out!
192
193 if (_connected)
|
194 kumpf 1.26 {
195 PEG_METHOD_EXIT();
|
196 kumpf 1.14 throw AlreadyConnectedException();
|
197 kumpf 1.26 }
|
198 kumpf 1.14
199 //
200 // If the host is empty, set hostName to "localhost"
201 //
202 String hostName = host;
203 if (host == String::EMPTY)
204 {
205 hostName = "localhost";
206 }
207
208 //
209 // Set authentication information
210 //
|
211 kumpf 1.23 _authenticator.clear();
|
212 kumpf 1.14
|
213 kumpf 1.28 _connectSSLContext.reset(0);
|
214 kumpf 1.14 _connectHost = hostName;
215 _connectPortNumber = portNumber;
216
217 _connect();
|
218 kumpf 1.26 PEG_METHOD_EXIT();
|
219 kumpf 1.14 }
220
|
221 kumpf 1.17 void CIMExportClient::connect(
222 const String& host,
223 const Uint32 portNumber,
224 const SSLContext& sslContext)
225 {
|
226 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::connect()");
227
228 // If already connected, bail out!
|
229 kumpf 1.17
|
230 kumpf 1.26 if (_connected)
231 {
232 PEG_METHOD_EXIT();
233 throw AlreadyConnectedException();
234 }
|
235 kumpf 1.17
236 //
237 // If the host is empty, set hostName to "localhost"
238 //
239 String hostName = host;
240 if (host == String::EMPTY)
241 {
242 hostName = "localhost";
243 }
244
245 //
246 // Set authentication information
247 //
|
248 kumpf 1.23 _authenticator.clear();
|
249 kumpf 1.17
|
250 kumpf 1.28 _connectSSLContext.reset(new SSLContext(sslContext));
|
251 kumpf 1.17 _connectHost = hostName;
252 _connectPortNumber = portNumber;
253
254 try
255 {
256 _connect();
257 }
|
258 kumpf 1.34 catch (...)
|
259 kumpf 1.17 {
|
260 kumpf 1.28 _connectSSLContext.reset();
|
261 kumpf 1.26 PEG_METHOD_EXIT();
|
262 kumpf 1.17 throw;
263 }
|
264 kumpf 1.26 PEG_METHOD_EXIT();
|
265 kumpf 1.17 }
266
|
267 kumpf 1.14 void CIMExportClient::disconnect()
|
268 mike 1.2 {
|
269 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::disconnect()");
|
270 kumpf 1.23 _disconnect();
271 _authenticator.clear();
|
272 kumpf 1.28 _connectSSLContext.reset();
|
273 kumpf 1.26 PEG_METHOD_EXIT();
|
274 mike 1.2 }
275
276 void CIMExportClient::exportIndication(
|
277 mday 1.4 const String& url,
|
278 chuck 1.16 const CIMInstance& instanceName,
|
279 kumpf 1.39 const ContentLanguageList& contentLanguages)
|
280 mike 1.2 {
|
281 carolann.graves 1.35 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::exportIndication()");
|
282 kumpf 1.26
|
283 carolann.graves 1.35 try
284 {
285 // encode request
286 // l10n
287 CIMRequestMessage* request = new CIMExportIndicationRequestMessage(
288 String::EMPTY,
289 url,
290 instanceName,
291 QueueIdStack(),
292 String::EMPTY,
293 String::EMPTY);
|
294 se.gupta 1.27
|
295 carolann.graves 1.35 request->operationContext.set
296 (ContentLanguageListContainer(contentLanguages));
|
297 mike 1.2
|
298 carolann.graves 1.35 Message* message = _doRequest(request,
299 CIM_EXPORT_INDICATION_RESPONSE_MESSAGE);
|
300 mike 1.2
|
301 carolann.graves 1.35 CIMExportIndicationResponseMessage* response =
302 (CIMExportIndicationResponseMessage*)message;
|
303 mike 1.2
|
304 carolann.graves 1.35 AutoPtr<CIMExportIndicationResponseMessage> ap(response);
305 }
306 catch (const Exception & e)
307 {
308 PEG_TRACE_STRING (TRC_DISCARDED_DATA, Tracer::LEVEL4,
309 "Failed to export indication: " + e.getMessage ());
310 throw;
311 }
312 catch (...)
313 {
314 PEG_TRACE_STRING (TRC_DISCARDED_DATA, Tracer::LEVEL4,
315 "Failed to export indication");
316 throw;
317 }
|
318 kumpf 1.26
|
319 carolann.graves 1.35 PEG_METHOD_EXIT();
|
320 mike 1.2 }
321
|
322 kumpf 1.14 Message* CIMExportClient::_doRequest(
323 CIMRequestMessage * request,
324 const Uint32 expectedResponseMessageType
325 )
|
326 mike 1.2 {
|
327 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_doRequest()");
328
|
329 kumpf 1.14 if (!_connected)
330 {
331 delete request;
|
332 kumpf 1.26 PEG_METHOD_EXIT();
|
333 kumpf 1.14 throw NotConnectedException();
334 }
335
336 String messageId = XmlWriter::getNextMessageId();
337 const_cast<String &>(request->messageId) = messageId;
338
|
339 kumpf 1.23 _authenticator.setRequestMessage(0);
|
340 kumpf 1.14
341 // ATTN-RK-P2-20020416: We should probably clear out the queue first.
342 PEGASUS_ASSERT(getCount() == 0); // Shouldn't be any messages in our queue
343
344 //
|
345 kumpf 1.22 // Set HTTP method in request to POST
|
346 kumpf 1.14 //
|
347 kumpf 1.22 request->setHttpMethod (HTTP_METHOD__POST);
|
348 kumpf 1.14
349 _requestEncoder->enqueue(request);
350
351 Uint64 startMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
352 Uint64 nowMilliseconds = startMilliseconds;
353 Uint64 stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;
354
355 while (nowMilliseconds < stopMilliseconds)
356 {
357 //
358 // Wait until the timeout expires or an event occurs:
359 //
|
360 kumpf 1.31 _monitor->run(Uint32(stopMilliseconds - nowMilliseconds));
|
361 kumpf 1.14
362 //
363 // Check to see if incoming queue has a message
364 //
365
366 Message* response = dequeue();
367
368 if (response)
369 {
370 // Shouldn't be any more messages in our queue
371 PEGASUS_ASSERT(getCount() == 0);
372
373 //
|
374 kumpf 1.21 // Future: If M-POST is used and HTTP response is 501 Not
375 // Implemented or 510 Not Extended, retry with POST method
|
376 kumpf 1.14 //
|
377 j.alex 1.37 //
378
379 // Reconnect to reset the connection
380 // if Server response contained a Connection: Close Header
381 //
|
382 j.alex 1.38 if (response->getCloseConnect() == true){
383 _reconnect();
384 response->setCloseConnect(false);
|
385 j.alex 1.37 }
386
|
387 kumpf 1.14
388 if (response->getType() == CLIENT_EXCEPTION_MESSAGE)
389 {
390 Exception* clientException =
391 ((ClientExceptionMessage*)response)->clientException;
392 delete response;
|
393 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Client Exception Message received.");
|
394 kumpf 1.21
|
395 joyce.j 1.33 AutoPtr<Exception> d(clientException);
|
396 kumpf 1.21
397 //
398 // Determine and throw the specific class of client exception
399 //
400
401 CIMClientMalformedHTTPException* malformedHTTPException =
402 dynamic_cast<CIMClientMalformedHTTPException*>(
403 clientException);
404 if (malformedHTTPException)
405 {
|
406 kumpf 1.26 PEG_METHOD_EXIT();
|
407 kumpf 1.21 throw *malformedHTTPException;
408 }
409
410 CIMClientHTTPErrorException* httpErrorException =
411 dynamic_cast<CIMClientHTTPErrorException*>(
412 clientException);
413 if (httpErrorException)
414 {
|
415 kumpf 1.26 PEG_METHOD_EXIT();
|
416 kumpf 1.21 throw *httpErrorException;
417 }
418
419 CIMClientXmlException* xmlException =
420 dynamic_cast<CIMClientXmlException*>(clientException);
421 if (xmlException)
422 {
|
423 kumpf 1.26 PEG_METHOD_EXIT();
|
424 kumpf 1.21 throw *xmlException;
425 }
426
427 CIMClientResponseException* responseException =
428 dynamic_cast<CIMClientResponseException*>(clientException);
429 if (responseException)
430 {
|
431 kumpf 1.26 PEG_METHOD_EXIT();
|
432 kumpf 1.21 throw *responseException;
433 }
434
|
435 kumpf 1.26 PEG_METHOD_EXIT();
|
436 kumpf 1.14 throw *clientException;
437 }
438 else if (response->getType() == expectedResponseMessageType)
439 {
|
440 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4,
|
441 carolann.graves 1.35 "Received expected indication response message.");
|
442 kumpf 1.14 CIMResponseMessage* cimResponse = (CIMResponseMessage*)response;
443 if (cimResponse->messageId != messageId)
444 {
|
445 humberto 1.18 // l10n
446
447 // CIMClientResponseException responseException(
448 // String("Mismatched response message ID: Got \"") +
449 // cimResponse->messageId + "\", expected \"" +
450 // messageId + "\".");
451
452 MessageLoaderParms mlParms("ExportClient.CIMExportClient.MISMATCHED_RESPONSE_ID",
|
453 kumpf 1.26 "Mismatched response message ID: Got \"$0\", expected \"$1\".",
454 cimResponse->messageId, messageId);
|
455 humberto 1.18 String mlString(MessageLoader::getMessage(mlParms));
456
457 CIMClientResponseException responseException(mlString);
458
459 delete response;
|
460 kumpf 1.26 PEG_METHOD_EXIT();
|
461 humberto 1.18 throw responseException;
|
462 kumpf 1.14 }
463 if (cimResponse->cimException.getCode() != CIM_ERR_SUCCESS)
464 {
|
465 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4,
466 "Received indication failure message.");
|
467 kumpf 1.14 CIMException cimException(
468 cimResponse->cimException.getCode(),
469 cimResponse->cimException.getMessage());
470 delete response;
|
471 kumpf 1.26 PEG_METHOD_EXIT();
|
472 kumpf 1.14 throw cimException;
473 }
|
474 kumpf 1.26 PEG_METHOD_EXIT();
|
475 kumpf 1.14 return response;
476 }
|
477 j.alex 1.38 else if (dynamic_cast<CIMRequestMessage*>(response) != 0)
478 {
479 // Respond to an authentication challenge
480 _requestEncoder->enqueue(response);
481 nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
482 stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;
483 continue;
484 }
|
485 kumpf 1.14 else
486 {
|
487 humberto 1.18 // l10n
488
489 // CIMClientResponseException responseException(
490 // "Mismatched response message type.");
491
492 MessageLoaderParms mlParms("ExportClient.CIMExportClient.MISMATCHED_RESPONSE",
493 "Mismatched response message type.");
494 String mlString(MessageLoader::getMessage(mlParms));
495
496 CIMClientResponseException responseException(mlString);
497
498 delete response;
|
499 kumpf 1.26
500 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, mlString);
501
502 PEG_METHOD_EXIT();
|
503 humberto 1.18 throw responseException;
|
504 kumpf 1.14 }
505 }
506
507 nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
|
508 mike 1.43 Threads::yield();
|
509 kumpf 1.14 }
510
511 //
512 // Reconnect to reset the connection (disregard late response)
513 //
514 try
515 {
|
516 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Doing a _reconnect()...");
|
517 kumpf 1.14 _reconnect();
518 }
519 catch (...)
520 {
521 }
522
|
523 carolann.graves 1.35 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Connection to the listener timed out.");
|
524 kumpf 1.26 PEG_METHOD_EXIT();
|
525 kumpf 1.14 //
526 // Throw timed out exception:
527 //
528 throw ConnectionTimeoutException();
|
529 mike 1.2 }
530
531 PEGASUS_NAMESPACE_END
|