1 karl 1.16 //%2005////////////////////////////////////////////////////////////////////////
|
2 mike 1.4 //
|
3 karl 1.15 // 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.14 // IBM Corp.; EMC Corporation, The Open Group.
|
7 karl 1.15 // 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.16 // Copyright (c) 2005 Hewlett-Packard Development Company, L.P.; IBM Corp.;
10 // EMC Corporation; VERITAS Software Corporation; The Open Group.
|
11 mike 1.4 //
12 // Permission is hereby granted, free of charge, to any person obtaining a copy
|
13 kumpf 1.6 // of this software and associated documentation files (the "Software"), to
14 // deal in the Software without restriction, including without limitation the
15 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
16 mike 1.4 // sell copies of the Software, and to permit persons to whom the Software is
17 // furnished to do so, subject to the following conditions:
|
18 david.dillard 1.18 //
|
19 kumpf 1.6 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN
|
20 mike 1.4 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED
21 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
22 kumpf 1.6 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
23 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
24 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
25 mike 1.4 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //==============================================================================
29 //
30 // Author: Mike Brasher (mbrasher@bmc.com)
31 //
|
32 kumpf 1.10 // Modified By: Carol Ann Krug Graves, Hewlett-Packard Company
|
33 david.dillard 1.18 // (carolann_graves@hp.com)
|
34 kumpf 1.13 // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com)
|
35 david.dillard 1.18 // David Dillard, VERITAS Software Corp.
36 // (david.dillard@veritas.com)
|
37 r.kieninger 1.19 // Robert Kieninger, IBM (kieningr@de.ibm.com)
|
38 mike 1.4 //
39 //%/////////////////////////////////////////////////////////////////////////////
40
|
41 mike 1.5 #include <Pegasus/Common/Config.h>
|
42 kumpf 1.8 #include <Pegasus/Common/InternalException.h>
|
43 mike 1.4 #include <Pegasus/Common/FileSystem.h>
44 #include <Pegasus/Common/Exception.h>
45 #include "AssocClassTable.h"
46
47 PEGASUS_USING_STD;
48
49 PEGASUS_NAMESPACE_BEGIN
50
51 #define ASSOC_CLASS_NAME_INDEX 0
52 #define FROM_CLASS_NAME_INDEX 1
53 #define FROM_PROPERTY_NAME_INDEX 2
54 #define TO_CLASS_NAME_INDEX 3
55 #define TO_PROPERTY_NAME_INDEX 4
56 #define NUM_FIELDS 5
57
|
58 r.kieninger 1.19
59 ReadWriteSem AssocClassTable::_classCacheLock;
60
61
|
62 mike 1.4 static inline Boolean _MatchNoCase(const String& x, const String& pattern)
63 {
64 return pattern.size() == 0 || String::equalNoCase(x, pattern);
65 }
66
|
67 david.dillard 1.18 static inline Boolean _ContainsClass(const Array<CIMName>& classNames, const String& match )
|
68 karl 1.11 {
69 Uint32 n = classNames.size();
70
71 for (Uint32 i = 0; i < n; i++)
72 {
|
73 david.dillard 1.18 if (_MatchNoCase(classNames[i].getString(), match))
74 return true;
|
75 karl 1.11 }
76
77 return false;
78 }
79
80
|
81 mike 1.4 static String _Escape(const String& str)
82 {
83 String result;
84
85 for (Uint32 i = 0, n = str.size(); i < n; i++)
86 {
87 Char16 c = str[i];
88
89 switch (c)
90 {
91 case '\n':
|
92 kumpf 1.9 result.append("\\n");
|
93 mike 1.4 break;
94
95 case '\r':
|
96 kumpf 1.9 result.append("\\r");
|
97 mike 1.4 break;
98
99 case '\t':
|
100 kumpf 1.9 result.append("\\t");
|
101 mike 1.4 break;
102
103 case '\f':
|
104 kumpf 1.9 result.append("\\f");
|
105 mike 1.4 break;
106
107 case '\\':
|
108 kumpf 1.9 result.append("\\\\");
|
109 mike 1.4 break;
110
111 default:
|
112 kumpf 1.9 result.append(c);
|
113 mike 1.4 }
114 }
115
116 return result;
117 }
118
119 static String _Unescape(const String& str)
120 {
121 String result;
122
123 for (Uint32 i = 0, n = str.size(); i < n; i++)
124 {
125 Char16 c = str[i];
126
127 if (c == '\\')
128 {
129 if (i + 1 == n)
130 break;
131
132 c = str[i + 1];
133
134 mike 1.4 switch (c)
135 {
136 case 'n':
|
137 kumpf 1.9 result.append("\n");
|
138 mike 1.4 break;
139
140 case 'r':
|
141 kumpf 1.9 result.append("\r");
|
142 mike 1.4 break;
143
144 case 't':
|
145 kumpf 1.9 result.append("\t");
|
146 mike 1.4 break;
147
148 case 'f':
|
149 kumpf 1.9 result.append("\f");
|
150 mike 1.4 break;
151
152 default:
|
153 kumpf 1.9 result.append(c);
|
154 mike 1.4 }
155
156 i++;
157 }
158 else
|
159 kumpf 1.9 result.append(c);
|
160 mike 1.4 }
161
162 return result;
163 }
164
165 static Boolean _GetRecord(ifstream& is, Array<String>& fields)
166 {
167 fields.clear();
168 String line;
169
170 for (Uint32 i = 0; i < NUM_FIELDS; i++)
171 {
172 if (!GetLine(is, line))
173 return false;
174
|
175 r.kieninger 1.19 fields.append(line);
176 //Association names are not supposed to contain escapes
177 //fields.append(_Unescape(line));
|
178 mike 1.4 }
179
180 // Skip the blank line:
181
182 if (!GetLine(is, line))
183 return false;
184
185 return true;
186 }
187
188 static void _PutRecord(ofstream& os, Array<String>& fields)
189 {
190 for (Uint32 i = 0, n = fields.size(); i < n; i++)
|
191 chuck 1.17 {
192 // Calling getCString to ensure utf-8 goes to the file
193 // Calling write to ensure no data conversion by the stream
|
194 david.dillard 1.18 CString buffer = _Escape(fields[i]).getCString();
|
195 chuck 1.17 #ifdef PEGASUS_PLATFORM_HPUX_PARISC_ACC
196 os.write((const char *)buffer, strlen((const char *)buffer));
197 #else
198 os.write((const char *)buffer, static_cast<streamsize>(strlen((const char *)buffer)));
|
199 david.dillard 1.18 #endif
|
200 chuck 1.17 os << endl;
201 }
|
202 mike 1.4 os << endl;
203 }
204
205 void AssocClassTable::append(
206 PEGASUS_STD(ofstream)& os,
|
207 r.kieninger 1.19 const String& path,
|
208 kumpf 1.10 const CIMName& assocClassName,
209 const CIMName& fromClassName,
210 const CIMName& fromPropertyName,
211 const CIMName& toClassName,
212 const CIMName& toPropertyName)
|
213 mike 1.4 {
214 Array<String> fields;
|
215 kumpf 1.7 fields.reserveCapacity(5);
|
216 kumpf 1.10 fields.append(assocClassName.getString());
217 fields.append(fromClassName.getString());
218 fields.append(fromPropertyName.getString());
219 fields.append(toClassName.getString());
220 fields.append(toPropertyName.getString());
|
221 mike 1.4
|
222 r.kieninger 1.19 for (Uint16 x=0; x<fields.size();x++)
223 {
224 fields[x].toLower();
225 }
226
|
227 mike 1.4 _PutRecord(os, fields);
|
228 r.kieninger 1.19
229 // Update cache
230 AssocClassCache *cache = AssocClassCache::getAssocClassCache(path);
231 if (cache != 0)
232 {
233 if (cache->isActive())
234 {
235 WriteLock lock(_classCacheLock);
236 cache->addRecord(fields[FROM_CLASS_NAME_INDEX],
237 fields);
238 }
239 }
|
240 mike 1.4 }
241
242 void AssocClassTable::append(
243 const String& path,
|
244 kumpf 1.10 const CIMName& assocClassName,
245 const CIMName& fromClassName,
246 const CIMName& fromPropertyName,
247 const CIMName& toClassName,
248 const CIMName& toPropertyName)
|
249 mike 1.4 {
250 // Open input file:
|
251 david.dillard 1.18
|
252 mike 1.4 ofstream os;
253
254 if (!OpenAppend(os, path))
255 throw CannotOpenFile(path);
256
257 // Insert the entry:
258
259 Array<String> fields;
|
260 kumpf 1.7 fields.reserveCapacity(5);
|
261 kumpf 1.10 fields.append(assocClassName.getString());
262 fields.append(fromClassName.getString());
263 fields.append(fromPropertyName.getString());
264 fields.append(toClassName.getString());
265 fields.append(toPropertyName.getString());
|
266 mike 1.4
|
267 r.kieninger 1.19 for (Uint16 x=0; x<fields.size();x++)
268 {
269 fields[x].toLower();
270 }
271
|
272 mike 1.4 _PutRecord(os, fields);
|
273 r.kieninger 1.19
274 // Update cache
275 AssocClassCache *cache = AssocClassCache::getAssocClassCache(path);
276 if (cache != 0)
277 {
278 if (cache->isActive())
279 {
280 WriteLock lock(_classCacheLock);
281 cache->addRecord(fields[FROM_CLASS_NAME_INDEX],
282 fields);
283 }
284 }
|
285 mike 1.4 }
286
287 Boolean AssocClassTable::deleteAssociation(
288 const String& path,
|
289 kumpf 1.10 const CIMName& assocClassName)
|
290 mike 1.4 {
291 // Open input file:
292
293 ifstream is;
294
295 if (!Open(is, path))
296 return false;
297
298 // Open output file:
299
300 String tmpPath = path + ".tmp";
301 ofstream os;
302
303 if (!Open(os, tmpPath))
304 throw CannotOpenFile(tmpPath);
305
306 // Copy over all lines except ones with the given association instance name:
307
308 Array<String> fields;
|
309 r.kieninger 1.19 Array<String> fieldsToDelete;
|
310 mike 1.4 Boolean found = false;
311
312 while (_GetRecord(is, fields))
313 {
|
314 kumpf 1.10 if (assocClassName.getString() != fields[ASSOC_CLASS_NAME_INDEX])
|
315 mike 1.4 {
316 _PutRecord(os, fields);
317 found = true;
318 }
|
319 r.kieninger 1.19 else
320 {
321 fieldsToDelete = fields;
322 }
|
323 mike 1.4 }
324
325 // Close both files:
326
327 is.close();
328 os.close();
329
330 // Remove orginal file:
331
332 if (!FileSystem::removeFile(path))
333 throw CannotRemoveFile(path);
334
335 // Rename back to original name:
336
337 if (!FileSystem::renameFile(tmpPath, path))
338 throw CannotRenameFile(path);
339
|
340 r.kieninger 1.19
341 // Update cache
342 if (found)
343 {
344 AssocClassCache *cache = AssocClassCache::getAssocClassCache(path);
345 if (cache != 0)
346 {
347 if (cache->isActive())
348 {
349 WriteLock lock(_classCacheLock);
350 cache->removeRecord(fieldsToDelete[FROM_CLASS_NAME_INDEX],
351 fieldsToDelete[ASSOC_CLASS_NAME_INDEX]);
352 }
353 }
354 }
355
|
356 mike 1.4 return found;
357 }
358
359 Boolean AssocClassTable::getAssociatorNames(
360 const String& path,
|
361 kumpf 1.13 const Array<CIMName>& classList,
362 const Array<CIMName>& assocClassList,
363 const Array<CIMName>& resultClassList,
|
364 mike 1.4 const String& role,
365 const String& resultRole,
366 Array<String>& associatorNames)
367 {
368 // Open input file:
369 ifstream is;
370
371 if (!Open(is, path))
|
372 kumpf 1.13 return false;
|
373 mike 1.4
374 Array<String> fields;
375 Boolean found = false;
376
|
377 kumpf 1.13 // For each line in the associations table:
|
378 mike 1.4 while (_GetRecord(is, fields))
379 {
|
380 kumpf 1.13 // Process associations from the right end class and with right roles
381 if (_ContainsClass(classList, fields[FROM_CLASS_NAME_INDEX]) &&
382 _MatchNoCase(fields[FROM_PROPERTY_NAME_INDEX], role) &&
383 _MatchNoCase(fields[TO_PROPERTY_NAME_INDEX], resultRole))
384 {
385 // Skip classes that do not appear in the association class list
386 if ((assocClassList.size() != 0) &&
387 (!_ContainsClass(assocClassList,
388 fields[ASSOC_CLASS_NAME_INDEX])))
389 {
390 continue;
391 }
392
393 // Skip classes that do not appear in the result class list
394 if ((resultClassList.size() != 0) &&
395 (!_ContainsClass(resultClassList,
396 fields[TO_CLASS_NAME_INDEX])))
397 {
398 continue;
399 }
400
401 kumpf 1.13 // This class qualifies; add it to the list (skipping duplicates)
402 if (!Contains(associatorNames, fields[TO_CLASS_NAME_INDEX]))
403 {
404 associatorNames.append(fields[TO_CLASS_NAME_INDEX]);
405 }
406 found = true;
407 }
|
408 mike 1.4 }
409
410 return found;
411 }
412
|
413 r.kieninger 1.19 Boolean AssocClassTable::_InitializeCache( AssocClassCache *cache,
414 const String& path)
415 {
416 WriteLock lock(_classCacheLock);
417
418 if (!cache->isActive())
419 {
420
421 // Open input file:
422 ifstream is;
423
424 if (!Open(is, path))
425 return false;
426
427 Array<String> fields;
428
429 // For each line in the associations table:
430 while (_GetRecord(is, fields))
431 {
432 // The cache key is always expected to be in lowercase
433 // While new association records are added in lowercase,
434 r.kieninger 1.19 // the following line is required for compatibility
435 // with old repositories.
436 fields[FROM_CLASS_NAME_INDEX].toLower();
437 cache->addRecord(fields[FROM_CLASS_NAME_INDEX],
438 fields);
439 }
440
441 cache->setActive(true);
442 }
443
444 return true;
445 }
446
447 void AssocClassTable::removeCaches()
448 {
449 WriteLock lock(_classCacheLock);
450 AssocClassCache::cleanupAssocClassCaches();
451
452 return;
453 }
454
|
455 mike 1.4 Boolean AssocClassTable::getReferenceNames(
456 const String& path,
|
457 karl 1.11 const Array<CIMName>& classList,
|
458 kumpf 1.13 const Array<CIMName>& resultClassList,
|
459 mike 1.4 const String& role,
460 Array<String>& referenceNames)
461 {
462
|
463 r.kieninger 1.19 // First see if we can get the information from the association class cache.
464 AssocClassCache *cache = AssocClassCache::getAssocClassCache(path);
465 if (cache == 0)
|
466 kumpf 1.13 return false;
|
467 mike 1.4
|
468 r.kieninger 1.19 if (!cache->isActive())
469 {
470 if (!_InitializeCache(cache,path))
471 return false;
472 }
473
474 Array< Array<String> > records;
|
475 karl 1.11 Boolean found = false;
476
|
477 r.kieninger 1.19
478 // For each of the target classes retrieve the list of matching
479 // association classes from the cache.
480 // The cache uses the from class name as an index and returns all
481 // association class records having that from class.
482
483 ReadLock lock(_classCacheLock);
484 for (Uint16 idx=0; idx < classList.size(); idx++)
|
485 karl 1.11 {
|
486 r.kieninger 1.19 String fromClassName = classList[idx].getString();
487 fromClassName.toLower();
488 if (cache->getAssocClassEntry(fromClassName, records))
489 {
490 for (Uint16 rx=0; rx <records.size(); rx++)
491 {
492 if (_MatchNoCase(records[rx][FROM_PROPERTY_NAME_INDEX], role))
|
493 kumpf 1.13 {
494 // Skip classes that do not appear in the result class list
495 if ((resultClassList.size() != 0) &&
496 (!_ContainsClass(resultClassList,
|
497 r.kieninger 1.19 records[rx][ASSOC_CLASS_NAME_INDEX])))
|
498 kumpf 1.13 {
499 continue;
500 }
|
501 karl 1.11
|
502 kumpf 1.13 // This class qualifies; add it to the list (skipping duplicates)
|
503 r.kieninger 1.19 if (!Contains(referenceNames, records[rx][ASSOC_CLASS_NAME_INDEX]))
|
504 karl 1.11 {
|
505 r.kieninger 1.19 referenceNames.append(records[rx][ASSOC_CLASS_NAME_INDEX]);
|
506 karl 1.11 }
|
507 kumpf 1.13 found = true;
|
508 karl 1.11 }
|
509 mike 1.4 }
|
510 r.kieninger 1.19 }
511 }
|
512 mike 1.4
513 return found;
514 }
515
516 PEGASUS_NAMESPACE_END
|