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
22 #include "SaxObjectModel.h"
25 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
26 APPLE_FOUNDATION_LIBRARY
27 bool _CFArrayIsMutable(CFArrayRef dict);
30 static NSDictionary *mapDictsToObjects(NSDictionary *_dict, Class clazz) {
31 NSMutableDictionary *md;
35 md = [NSMutableDictionary dictionaryWithCapacity:16];
37 e = [_dict keyEnumerator];
38 while ((key = [e nextObject])) {
41 obj = [[clazz alloc] initWithDictionary:[_dict objectForKey:key]];
42 [md setObject:obj forKey:key];
48 @implementation SaxObjectModel
50 static BOOL doDebug = NO;
51 static NSArray *searchPathes = nil;
53 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
54 APPLE_FOUNDATION_LIBRARY
55 static Class NSCFArrayClass = Nil;
58 static BOOL isInitialized = NO;
60 if (isInitialized) return;
62 NSCFArrayClass = NSClassFromString(@"NSCFArray");
66 + (NSArray *)saxMappingSearchPathes {
67 if (searchPathes == nil) {
72 env = [[NSProcessInfo processInfo] environment];
73 ma = [NSMutableArray arrayWithCapacity:6];
75 #if COCOA_Foundation_LIBRARY
76 tmp = NSSearchPathForDirectoriesInDomains(NSAllLibrariesDirectory,
79 if ([tmp count] > 0) {
82 e = [tmp objectEnumerator];
83 while ((tmp = [e nextObject])) {
84 tmp = [tmp stringByAppendingPathComponent:@"SaxMappings"];
85 if (![ma containsObject:tmp])
90 if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
91 tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
92 tmp = [tmp componentsSeparatedByString:@":"];
93 if ([tmp count] > 0) {
96 e = [tmp objectEnumerator];
97 while ((tmp = [e nextObject])) {
98 tmp = [tmp stringByAppendingPathComponent:@"Library/SaxMappings"];
99 if (![ma containsObject:tmp])
106 [ma addObject:@"/usr/local/share/sope-4.3/saxmappings/"];
107 [ma addObject:@"/usr/share/sope-4.3/saxmappings/"];
108 searchPathes = [ma copy];
110 if ([searchPathes count] == 0)
111 NSLog(@"%s: no search pathes were found!", __PRETTY_FUNCTION__);
116 + (id)modelWithName:(NSString *)_name {
117 NSFileManager *fileManager;
118 NSEnumerator *pathes;
121 /* first look in main bundle */
123 if ((path = [[NSBundle mainBundle] pathForResource:_name ofType:@"xmap"]))
124 return [self modelWithContentsOfFile:path];
126 /* then in Library */
128 fileManager = [NSFileManager defaultManager];
129 pathes = [[[self class] saxMappingSearchPathes] objectEnumerator];
130 _name = [_name stringByAppendingPathExtension:@"xmap"];
132 while ((path = [pathes nextObject])) {
135 path = [path stringByAppendingPathComponent:_name];
137 if (![fileManager fileExistsAtPath:path isDirectory:&isDir])
145 return [self modelWithContentsOfFile:path];
148 + (id)modelWithContentsOfFile:(NSString *)_path {
151 if ((dict = [NSDictionary dictionaryWithContentsOfFile:_path]) == nil)
154 return [[[self alloc] initWithDictionary:dict] autorelease];
157 - (id)initWithDictionary:(NSDictionary *)_dict {
159 [mapDictsToObjects(_dict, [SaxNamespaceModel class]) retain];
164 [self->nsToModel release];
170 - (SaxTagModel *)modelForTag:(NSString *)_localName namespace:(NSString *)_ns {
171 SaxNamespaceModel *nsmap;
173 if ((nsmap = [self->nsToModel objectForKey:_ns]) == nil) {
174 if ((nsmap = [self->nsToModel objectForKey:@"*"]) == nil)
177 return [nsmap modelForTag:_localName];
180 /* faking dictionary */
182 - (id)objectForKey:(id)_key {
183 return [self->nsToModel objectForKey:_key];
186 @end /* SaxMappingModel */
188 @implementation SaxNamespaceModel
190 - (id)initWithDictionary:(NSDictionary *)_dict {
191 self->tagToModel = [mapDictsToObjects(_dict, [SaxTagModel class]) retain];
196 [self->tagToModel release];
202 - (SaxTagModel *)modelForTag:(NSString *)_localName {
205 if ((map = [self->tagToModel objectForKey:_localName]))
207 if ((map = [self->tagToModel objectForKey:@"*"]))
212 /* faking dictionary */
214 - (id)objectForKey:(id)_key {
215 return [self->tagToModel objectForKey:_key];
218 @end /* SaxNamespaceModel */
220 @implementation SaxTagModel
222 - (NSDictionary *)_extractAttributeMapping:(NSDictionary *)as {
223 NSMutableDictionary *md;
226 NSDictionary *result;
228 md = [[NSMutableDictionary alloc] initWithCapacity:16];
230 keys = [as keyEnumerator];
231 while ((k = [keys nextObject])) {
234 val = [as objectForKey:k];
236 if ([val isKindOfClass:[NSString class]])
237 [md setObject:val forKey:k];
238 else if ([val count] == 0)
239 [md setObject:k forKey:k];
241 [md setObject:[(NSDictionary *)val objectForKey:@"key"] forKey:k];
249 - (id)initWithDictionary:(NSDictionary *)_dict {
250 if ((self = [super init])) {
254 self->className = [[_dict objectForKey:@"class"] copy];
255 self->key = [[_dict objectForKey:@"key"] copy];
256 self->tagKey = [[_dict objectForKey:@"tagKey"] copy];
257 self->namespaceKey = [[_dict objectForKey:@"namespaceKey"] copy];
258 self->parentKey = [[_dict objectForKey:@"parentKey"] copy];
259 self->contentKey = [[_dict objectForKey:@"contentKey"] copy];
260 self->defaultValues = [[_dict objectForKey:@"defaultValues"] copy];
262 if ((as = [_dict objectForKey:@"attributes"]))
263 self->attrToKey = [self _extractAttributeMapping:as];
265 if ((rels = [_dict objectForKey:@"ToManyRelationships"])) {
266 NSMutableDictionary *md;
270 self->toManyRelationshipKeys = [[rels allKeys] copy];
272 md = [[NSMutableDictionary alloc] initWithCapacity:16];
274 keys = [self->toManyRelationshipKeys objectEnumerator];
275 while ((k = [keys nextObject])) {
279 tags = [rels objectForKey:k];
280 if ([tags isKindOfClass:[NSString class]])
281 tags = [NSArray arrayWithObject:tags];
282 tags = [tags objectEnumerator];
284 while ((tag = [tags nextObject])) {
287 if ((t = [md objectForKey:tag])) {
288 NSLog(@"SaxObjectModel: cannot map tag '%@' to key '%@', "
289 @"it is already mapped to key '%@'.",
293 [md setObject:k forKey:tag];
297 self->tagToKey = [md copy];
306 [self->defaultValues release];
307 [self->toManyRelationshipKeys release];
308 [self->tagToKey release];
309 [self->className release];
310 [self->tagKey release];
311 [self->namespaceKey release];
312 [self->parentKey release];
313 [self->contentKey release];
315 [self->attrToKey release];
321 - (NSString *)className {
322 return self->className;
327 - (NSString *)tagKey {
330 - (NSString *)namespaceKey {
331 return self->namespaceKey;
333 - (NSString *)parentKey {
334 return self->parentKey;
336 - (NSString *)contentKey {
337 return self->contentKey;
340 - (NSDictionary *)defaultValues {
341 return self->defaultValues;
344 - (BOOL)isToManyKey:(NSString *)_key {
345 return [self->toManyRelationshipKeys containsObject:_key];
347 - (NSArray *)toManyRelationshipKeys {
348 return self->toManyRelationshipKeys;
351 - (BOOL)isToManyTag:(NSString *)_tag {
352 return ([self->tagToKey objectForKey:_tag] != nil) ? YES : NO;
355 - (NSString *)propertyKeyForChildTag:(NSString *)_tag {
356 return [self->tagToKey objectForKey:_tag];
359 - (NSArray *)attributeKeys {
360 return [self->attrToKey allKeys];
362 - (NSString *)propertyKeyForAttribute:(NSString *)_attr {
363 return [self->attrToKey objectForKey:_attr];
366 /* object operations */
368 - (void)addValue:(id)_value toPropertyWithKey:(NSString *)_key
374 selname = [[NSString alloc] initWithFormat:@"addTo%@:",
375 [_key capitalizedString]];
376 if ((sel = NSSelectorFromString(selname)) == NULL) {
378 NSLog(@"got no selector for key '%@', selname '%@' !",
382 [selname release]; selname = nil;
385 NSLog(@"%s: adding value %@ to %@ of %@", __PRETTY_FUNCTION__,
386 _value, _key, _object);
387 NSLog(@" selector: %@", NSStringFromSelector(sel));
390 if ((sel != NULL) && [_object respondsToSelector:sel]) {
391 [_object performSelector:sel withObject:_value];
396 v = [_object valueForKey:_key];
398 if ([self isToManyKey:_key]) {
399 /* to-many relationship */
402 [_object takeValue:[NSArray arrayWithObject:_value] forKey:_key];
405 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY || \
406 APPLE_FOUNDATION_LIBRARY
407 if ([v isKindOfClass:NSCFArrayClass] &&
408 _CFArrayIsMutable((CFArrayRef)v))
410 if ([v respondsToSelector:@selector(addObject:)])
412 /* the value is mutable */
413 [v addObject:_value];
415 /* the value is immutable */
416 v = [v arrayByAddingObject:_value];
417 [_object takeValue:v forKey:_key];
422 NSLog(@" APPLIED ON TO-ONE (%@) !", _key);
423 /* to-one relationship */
425 [_object takeValue:v forKey:_key];
430 @end /* SaxTagModel */