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 kumpf 1.34 PEG_METHOD_EXIT();
|
140 mike 1.2 }
141
|
142 kumpf 1.23 void CIMExportClient::_disconnect()
143 {
|
144 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_disconnect()");
145
|
146 kumpf 1.23 if (_connected)
147 {
148 //
149 // destroy response decoder
150 //
|
151 kumpf 1.41 delete _responseDecoder;
152 _responseDecoder = 0;
|
153 kumpf 1.23
154 //
155 // Close the connection
156 //
157 if (_httpConnector)
158 {
159 _httpConnector->disconnect(_httpConnection);
160 _httpConnection = 0;
161 }
|
162 dj.gorey 1.24
|
163 kumpf 1.23
164 //
165 // destroy request encoder
166 //
|
167 kumpf 1.41 delete _requestEncoder;
168 _requestEncoder = 0;
|
169 kumpf 1.23
170 _connected = false;
171 }
|
172 kumpf 1.26 PEG_METHOD_EXIT();
|
173 kumpf 1.23 }
174
|
175 kumpf 1.14 void CIMExportClient::_reconnect()
176 {
|
177 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_reconnect()");
|
178 kumpf 1.23 _disconnect();
179 _authenticator.setRequestMessage(0);
|
180 kumpf 1.14 _connect();
|
181 kumpf 1.26 PEG_METHOD_EXIT();
|
182 kumpf 1.14 }
183
184 void CIMExportClient::connect(
185 const String& host,
186 const Uint32 portNumber)
187 {
|
188 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::connect()");
|
189 kumpf 1.14 // If already connected, bail out!
190
191 if (_connected)
|
192 kumpf 1.26 {
193 PEG_METHOD_EXIT();
|
194 kumpf 1.14 throw AlreadyConnectedException();
|
195 kumpf 1.26 }
|
196 kumpf 1.14
197 //
198 // If the host is empty, set hostName to "localhost"
199 //
200 String hostName = host;
201 if (host == String::EMPTY)
202 {
203 hostName = "localhost";
204 }
205
206 //
207 // Set authentication information
208 //
|
209 kumpf 1.23 _authenticator.clear();
|
210 kumpf 1.14
|
211 kumpf 1.28 _connectSSLContext.reset(0);
|
212 kumpf 1.14 _connectHost = hostName;
213 _connectPortNumber = portNumber;
214
215 _connect();
|
216 kumpf 1.26 PEG_METHOD_EXIT();
|
217 kumpf 1.14 }
218
|
219 kumpf 1.17 void CIMExportClient::connect(
220 const String& host,
221 const Uint32 portNumber,
222 const SSLContext& sslContext)
223 {
|
224 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::connect()");
225
226 // If already connected, bail out!
|
227 kumpf 1.17
|
228 kumpf 1.26 if (_connected)
229 {
230 PEG_METHOD_EXIT();
231 throw AlreadyConnectedException();
232 }
|
233 kumpf 1.17
234 //
235 // If the host is empty, set hostName to "localhost"
236 //
237 String hostName = host;
238 if (host == String::EMPTY)
239 {
240 hostName = "localhost";
241 }
242
243 //
244 // Set authentication information
245 //
|
246 kumpf 1.23 _authenticator.clear();
|
247 kumpf 1.17
|
248 kumpf 1.28 _connectSSLContext.reset(new SSLContext(sslContext));
|
249 kumpf 1.17 _connectHost = hostName;
250 _connectPortNumber = portNumber;
251
252 try
253 {
254 _connect();
255 }
|
256 kumpf 1.34 catch (...)
|
257 kumpf 1.17 {
|
258 kumpf 1.28 _connectSSLContext.reset();
|
259 kumpf 1.26 PEG_METHOD_EXIT();
|
260 kumpf 1.17 throw;
261 }
|
262 kumpf 1.26 PEG_METHOD_EXIT();
|
263 kumpf 1.17 }
264
|
265 kumpf 1.14 void CIMExportClient::disconnect()
|
266 mike 1.2 {
|
267 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::disconnect()");
|
268 kumpf 1.23 _disconnect();
269 _authenticator.clear();
|
270 kumpf 1.28 _connectSSLContext.reset();
|
271 kumpf 1.26 PEG_METHOD_EXIT();
|
272 mike 1.2 }
273
274 void CIMExportClient::exportIndication(
|
275 mday 1.4 const String& url,
|
276 chuck 1.16 const CIMInstance& instanceName,
|
277 kumpf 1.39 const ContentLanguageList& contentLanguages)
|
278 mike 1.2 {
|
279 carolann.graves 1.35 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::exportIndication()");
|
280 kumpf 1.26
|
281 carolann.graves 1.35 try
282 {
283 // encode request
284 // l10n
285 CIMRequestMessage* request = new CIMExportIndicationRequestMessage(
286 String::EMPTY,
287 url,
288 instanceName,
289 QueueIdStack(),
290 String::EMPTY,
291 String::EMPTY);
|
292 se.gupta 1.27
|
293 carolann.graves 1.35 request->operationContext.set
294 (ContentLanguageListContainer(contentLanguages));
|
295 mike 1.2
|
296 carolann.graves 1.35 Message* message = _doRequest(request,
297 CIM_EXPORT_INDICATION_RESPONSE_MESSAGE);
|
298 mike 1.2
|
299 carolann.graves 1.35 CIMExportIndicationResponseMessage* response =
300 (CIMExportIndicationResponseMessage*)message;
|
301 mike 1.2
|
302 carolann.graves 1.35 AutoPtr<CIMExportIndicationResponseMessage> ap(response);
303 }
304 catch (const Exception & e)
305 {
306 PEG_TRACE_STRING (TRC_DISCARDED_DATA, Tracer::LEVEL4,
307 "Failed to export indication: " + e.getMessage ());
308 throw;
309 }
310 catch (...)
311 {
312 PEG_TRACE_STRING (TRC_DISCARDED_DATA, Tracer::LEVEL4,
313 "Failed to export indication");
314 throw;
315 }
|
316 kumpf 1.26
|
317 carolann.graves 1.35 PEG_METHOD_EXIT();
|
318 mike 1.2 }
319
|
320 kumpf 1.14 Message* CIMExportClient::_doRequest(
321 CIMRequestMessage * request,
322 const Uint32 expectedResponseMessageType
323 )
|
324 mike 1.2 {
|
325 kumpf 1.26 PEG_METHOD_ENTER (TRC_EXPORT_CLIENT, "CIMExportClient::_doRequest()");
326
|
327 kumpf 1.14 if (!_connected)
328 {
329 delete request;
|
330 kumpf 1.26 PEG_METHOD_EXIT();
|
331 kumpf 1.14 throw NotConnectedException();
332 }
333
334 String messageId = XmlWriter::getNextMessageId();
335 const_cast<String &>(request->messageId) = messageId;
336
|
337 kumpf 1.23 _authenticator.setRequestMessage(0);
|
338 kumpf 1.14
339 // ATTN-RK-P2-20020416: We should probably clear out the queue first.
340 PEGASUS_ASSERT(getCount() == 0); // Shouldn't be any messages in our queue
341
342 //
|
343 kumpf 1.22 // Set HTTP method in request to POST
|
344 kumpf 1.14 //
|
345 kumpf 1.22 request->setHttpMethod (HTTP_METHOD__POST);
|
346 kumpf 1.14
347 _requestEncoder->enqueue(request);
348
349 Uint64 startMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
350 Uint64 nowMilliseconds = startMilliseconds;
351 Uint64 stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;
352
353 while (nowMilliseconds < stopMilliseconds)
354 {
355 //
356 // Wait until the timeout expires or an event occurs:
357 //
|
358 kumpf 1.31 _monitor->run(Uint32(stopMilliseconds - nowMilliseconds));
|
359 kumpf 1.14
360 //
361 // Check to see if incoming queue has a message
362 //
363
364 Message* response = dequeue();
365
366 if (response)
367 {
368 // Shouldn't be any more messages in our queue
369 PEGASUS_ASSERT(getCount() == 0);
370
371 //
|
372 kumpf 1.21 // Future: If M-POST is used and HTTP response is 501 Not
373 // Implemented or 510 Not Extended, retry with POST method
|
374 kumpf 1.14 //
|
375 j.alex 1.37 //
376
377 // Reconnect to reset the connection
378 // if Server response contained a Connection: Close Header
379 //
|
380 j.alex 1.38 if (response->getCloseConnect() == true){
381 _reconnect();
382 response->setCloseConnect(false);
|
383 j.alex 1.37 }
384
|
385 kumpf 1.14
386 if (response->getType() == CLIENT_EXCEPTION_MESSAGE)
387 {
388 Exception* clientException =
389 ((ClientExceptionMessage*)response)->clientException;
390 delete response;
|
391 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Client Exception Message received.");
|
392 kumpf 1.21
|
393 joyce.j 1.33 AutoPtr<Exception> d(clientException);
|
394 kumpf 1.21
395 //
396 // Determine and throw the specific class of client exception
397 //
398
399 CIMClientMalformedHTTPException* malformedHTTPException =
400 dynamic_cast<CIMClientMalformedHTTPException*>(
401 clientException);
402 if (malformedHTTPException)
403 {
|
404 kumpf 1.26 PEG_METHOD_EXIT();
|
405 kumpf 1.21 throw *malformedHTTPException;
406 }
407
408 CIMClientHTTPErrorException* httpErrorException =
409 dynamic_cast<CIMClientHTTPErrorException*>(
410 clientException);
411 if (httpErrorException)
412 {
|
413 kumpf 1.26 PEG_METHOD_EXIT();
|
414 kumpf 1.21 throw *httpErrorException;
415 }
416
417 CIMClientXmlException* xmlException =
418 dynamic_cast<CIMClientXmlException*>(clientException);
419 if (xmlException)
420 {
|
421 kumpf 1.26 PEG_METHOD_EXIT();
|
422 kumpf 1.21 throw *xmlException;
423 }
424
425 CIMClientResponseException* responseException =
426 dynamic_cast<CIMClientResponseException*>(clientException);
427 if (responseException)
428 {
|
429 kumpf 1.26 PEG_METHOD_EXIT();
|
430 kumpf 1.21 throw *responseException;
431 }
432
|
433 kumpf 1.26 PEG_METHOD_EXIT();
|
434 kumpf 1.14 throw *clientException;
435 }
436 else if (response->getType() == expectedResponseMessageType)
437 {
|
438 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4,
|
439 carolann.graves 1.35 "Received expected indication response message.");
|
440 kumpf 1.14 CIMResponseMessage* cimResponse = (CIMResponseMessage*)response;
441 if (cimResponse->messageId != messageId)
442 {
|
443 humberto 1.18 // l10n
444
445 // CIMClientResponseException responseException(
446 // String("Mismatched response message ID: Got \"") +
447 // cimResponse->messageId + "\", expected \"" +
448 // messageId + "\".");
449
450 MessageLoaderParms mlParms("ExportClient.CIMExportClient.MISMATCHED_RESPONSE_ID",
|
451 kumpf 1.26 "Mismatched response message ID: Got \"$0\", expected \"$1\".",
452 cimResponse->messageId, messageId);
|
453 humberto 1.18 String mlString(MessageLoader::getMessage(mlParms));
454
455 CIMClientResponseException responseException(mlString);
456
457 delete response;
|
458 kumpf 1.26 PEG_METHOD_EXIT();
|
459 humberto 1.18 throw responseException;
|
460 kumpf 1.14 }
461 if (cimResponse->cimException.getCode() != CIM_ERR_SUCCESS)
462 {
|
463 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4,
464 "Received indication failure message.");
|
465 kumpf 1.14 CIMException cimException(
466 cimResponse->cimException.getCode(),
467 cimResponse->cimException.getMessage());
468 delete response;
|
469 kumpf 1.26 PEG_METHOD_EXIT();
|
470 kumpf 1.14 throw cimException;
471 }
|
472 kumpf 1.26 PEG_METHOD_EXIT();
|
473 kumpf 1.14 return response;
474 }
|
475 j.alex 1.38 else if (dynamic_cast<CIMRequestMessage*>(response) != 0)
476 {
477 // Respond to an authentication challenge
478 _requestEncoder->enqueue(response);
479 nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
480 stopMilliseconds = nowMilliseconds + _timeoutMilliseconds;
481 continue;
482 }
|
483 kumpf 1.14 else
484 {
|
485 humberto 1.18 // l10n
486
487 // CIMClientResponseException responseException(
488 // "Mismatched response message type.");
489
490 MessageLoaderParms mlParms("ExportClient.CIMExportClient.MISMATCHED_RESPONSE",
491 "Mismatched response message type.");
492 String mlString(MessageLoader::getMessage(mlParms));
493
494 CIMClientResponseException responseException(mlString);
495
496 delete response;
|
497 kumpf 1.26
498 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, mlString);
499
500 PEG_METHOD_EXIT();
|
501 humberto 1.18 throw responseException;
|
502 kumpf 1.14 }
503 }
504
505 nowMilliseconds = TimeValue::getCurrentTime().toMilliseconds();
506 pegasus_yield();
507 }
508
509 //
510 // Reconnect to reset the connection (disregard late response)
511 //
512 try
513 {
|
514 kumpf 1.26 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Doing a _reconnect()...");
|
515 kumpf 1.14 _reconnect();
516 }
517 catch (...)
518 {
519 }
520
|
521 carolann.graves 1.35 PEG_TRACE_STRING(TRC_EXPORT_CLIENT, Tracer::LEVEL4, "Connection to the listener timed out.");
|
522 kumpf 1.26 PEG_METHOD_EXIT();
|
523 kumpf 1.14 //
524 // Throw timed out exception:
525 //
526 throw ConnectionTimeoutException();
|
527 mike 1.2 }
528
529 PEGASUS_NAMESPACE_END
|