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