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