2 Copyright (C) 2000-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "SaxObjectModel.h"
26 static NSDictionary *mapDictsToObjects(NSDictionary *_dict, Class clazz) {
27 NSMutableDictionary *md;
31 md = [NSMutableDictionary dictionaryWithCapacity:16];
33 e = [_dict keyEnumerator];
34 while ((key = [e nextObject])) {
37 obj = [[clazz alloc] initWithDictionary:[_dict objectForKey:key]];
38 [md setObject:obj forKey:key];
44 @implementation SaxObjectModel
46 static BOOL doDebug = NO;
47 static NSArray *searchPathes = nil;
49 + (NSArray *)saxMappingSearchPathes {
50 if (searchPathes == nil) {
55 env = [[NSProcessInfo processInfo] environment];
56 ma = [NSMutableArray arrayWithCapacity:6];
58 #if COCOA_Foundation_LIBRARY
59 tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
62 if ([tmp count] > 0) {
65 e = [tmp objectEnumerator];
66 while ((tmp = [e nextObject])) {
67 tmp = [tmp stringByAppendingPathComponent:@"SaxMappings"];
68 if (![ma containsObject:tmp])
73 if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
74 tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
75 tmp = [tmp componentsSeparatedByString:@":"];
76 if ([tmp count] > 0) {
79 e = [tmp objectEnumerator];
80 while ((tmp = [e nextObject])) {
81 tmp = [tmp stringByAppendingPathComponent:@"Library/SaxMappings"];
82 if (![ma containsObject:tmp])
87 NSLog(@"%s: empty library search path !", __PRETTY_FUNCTION__);
91 searchPathes = [ma copy];
93 if ([searchPathes count] == 0)
94 NSLog(@"%s: no search pathes were found !", __PRETTY_FUNCTION__);
99 + (id)modelWithName:(NSString *)_name {
100 NSFileManager *fileManager;
101 NSEnumerator *pathes;
104 /* first look in main bundle */
106 if ((path = [[NSBundle mainBundle] pathForResource:_name ofType:@"xmap"]))
107 return [self modelWithContentsOfFile:path];
109 /* then in Library */
111 fileManager = [NSFileManager defaultManager];
112 pathes = [[[self class] saxMappingSearchPathes] objectEnumerator];
113 _name = [_name stringByAppendingPathExtension:@"xmap"];
115 while ((path = [pathes nextObject])) {
118 path = [path stringByAppendingPathComponent:_name];
120 if (![fileManager fileExistsAtPath:path isDirectory:&isDir])
128 return [self modelWithContentsOfFile:path];
131 + (id)modelWithContentsOfFile:(NSString *)_path {
134 if ((dict = [NSDictionary dictionaryWithContentsOfFile:_path]) == nil)
137 return [[[self alloc] initWithDictionary:dict] autorelease];
140 - (id)initWithDictionary:(NSDictionary *)_dict {
142 [mapDictsToObjects(_dict, [SaxNamespaceModel class]) retain];
147 [self->nsToModel release];
153 - (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns {
154 SaxNamespaceModel *nsmap;
156 if ((nsmap = [self->nsToModel objectForKey:_ns]) == nil) {
157 if ((nsmap = [self->nsToModel objectForKey:@"*"]) == nil)
160 return [nsmap modelForTag:_localName];
163 /* faking dictionary */
165 - (id)objectForKey:(id)_key {
166 return [self->nsToModel objectForKey:_key];
169 @end /* SaxMappingModel */
171 @implementation SaxNamespaceModel
173 - (id)initWithDictionary:(NSDictionary *)_dict {
174 self->tagToModel = [mapDictsToObjects(_dict, [SaxTagModel class]) retain];
179 [self->tagToModel release];
185 - (SaxTagModel *)modelForTag:(NSString *)_localName {
188 if ((map = [self->tagToModel objectForKey:_localName]))
190 if ((map = [self->tagToModel objectForKey:@"*"]))
195 /* faking dictionary */
197 - (id)objectForKey:(id)_key {
198 return [self->tagToModel objectForKey:_key];
201 @end /* SaxNamespaceModel */
203 @implementation SaxTagModel
205 - (NSDictionary *)_extractAttributeMapping:(NSDictionary *)as {
206 NSMutableDictionary *md;
209 NSDictionary *result;
211 md = [[NSMutableDictionary alloc] initWithCapacity:16];
213 keys = [as keyEnumerator];
214 while ((k = [keys nextObject])) {
217 val = [as objectForKey:k];
219 if ([val isKindOfClass:[NSString class]])
220 [md setObject:val forKey:k];
221 else if ([val count] == 0)
222 [md setObject:k forKey:k];
224 [md setObject:[(NSDictionary *)val objectForKey:@"key"] forKey:k];
232 - (id)initWithDictionary:(NSDictionary *)_dict {
233 if ((self = [super init])) {
237 self->className = [[_dict objectForKey:@"class"] copy];
238 self->key = [[_dict objectForKey:@"key"] copy];
239 self->tagKey = [[_dict objectForKey:@"tagKey"] copy];
240 self->namespaceKey = [[_dict objectForKey:@"namespaceKey"] copy];
241 self->parentKey = [[_dict objectForKey:@"parentKey"] copy];
242 self->contentKey = [[_dict objectForKey:@"contentKey"] copy];
243 self->defaultValues = [[_dict objectForKey:@"defaultValues"] copy];
245 if ((as = [_dict objectForKey:@"attributes"]))
246 self->attrToKey = [self _extractAttributeMapping:as];
248 if ((rels = [_dict objectForKey:@"ToManyRelationships"])) {
249 NSMutableDictionary *md;
253 self->toManyRelationshipKeys = [[rels allKeys] copy];
255 md = [[NSMutableDictionary alloc] initWithCapacity:16];
257 keys = [self->toManyRelationshipKeys objectEnumerator];
258 while ((k = [keys nextObject])) {
262 tags = [rels objectForKey:k];
263 if ([tags isKindOfClass:[NSString class]])
264 tags = [NSArray arrayWithObject:tags];
265 tags = [tags objectEnumerator];
267 while ((tag = [tags nextObject])) {
270 if ((t = [md objectForKey:tag])) {
271 NSLog(@"SaxObjectModel: cannot map tag '%@' to key '%@', "
272 @"it is already mapped to key '%@'.",
276 [md setObject:k forKey:tag];
280 self->tagToKey = [md copy];
289 [self->defaultValues release];
290 [self->toManyRelationshipKeys release];
291 [self->tagToKey release];
292 [self->className release];
293 [self->tagKey release];
294 [self->namespaceKey release];
295 [self->parentKey release];
296 [self->contentKey release];
298 [self->attrToKey release];
304 - (NSString *)className {
305 return self->className;
310 - (NSString *)tagKey {
313 - (NSString *)namespaceKey {
314 return self->namespaceKey;
316 - (NSString *)parentKey {
317 return self->parentKey;
319 - (NSString *)contentKey {
320 return self->contentKey;
323 - (NSDictionary *)defaultValues {
324 return self->defaultValues;
327 - (BOOL)isToManyKey:(NSString *)_key {
328 return [self->toManyRelationshipKeys containsObject:_key];
330 - (NSArray *)toManyRelationshipKeys {
331 return self->toManyRelationshipKeys;
334 - (BOOL)isToManyTag:(NSString *)_tag {
335 return ([self->tagToKey objectForKey:_tag] != nil) ? YES : NO;
338 - (NSString *)propertyKeyForChildTag:(NSString *)_tag {
339 return [self->tagToKey objectForKey:_tag];
342 - (NSArray *)attributeKeys {
343 return [self->attrToKey allKeys];
345 - (NSString *)propertyKeyForAttribute:(NSString *)_attr {
346 return [self->attrToKey objectForKey:_attr];
349 /* object operations */
351 - (void)addValue:(id)_value toPropertyWithKey:(NSString *)_key
357 selname = [[NSString alloc] initWithFormat:@"addTo%@:",
358 [_key capitalizedString]];
359 if ((sel = NSSelectorFromString(selname)) == NULL) {
361 NSLog(@"got no selector for key '%@', selname '%@' !",
365 [selname release]; selname = nil;
368 NSLog(@"%s: adding value %@ to %@ of %@", __PRETTY_FUNCTION__,
369 _value, _key, _object);
370 NSLog(@" selector: %@", NSStringFromSelector(sel));
373 if ((sel != NULL) && [_object respondsToSelector:sel]) {
374 [_object performSelector:sel withObject:_value];
379 v = [_object valueForKey:_key];
381 if ([self isToManyKey:_key]) {
382 /* to-many relationship */
385 [_object takeValue:[NSArray arrayWithObject:_value] forKey:_key];
388 if ([v respondsToSelector:@selector(addObject:)])
389 /* the value is mutable */
390 [v addObject:_value];
392 /* the value is immutable */
393 v = [v arrayByAddingObject:_value];
394 [_object takeValue:v forKey:_key];
399 NSLog(@" APPLIED ON TO-ONE (%@) !", _key);
400 /* to-one relationship */
402 [_object takeValue:v forKey:_key];
407 @end /* SaxTagModel */