2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
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 "SoObject+SoDAV.h"
25 #include "SoObjectDataSource.h"
26 #include "EOFetchSpecification+SoDAV.h"
27 #include <NGObjWeb/WOApplication.h>
28 #include <NGObjWeb/WOContext.h>
29 #include <NGObjWeb/WEClientCapabilities.h>
30 #include <EOControl/EOQualifier.h>
31 #include <EOControl/EOSortOrdering.h>
34 @implementation NSObject(SoObjectDAVQueries)
36 static int debugBulk = NO; // TODO: set to -1 and use defaults
38 - (NSEnumerator *)davChildKeysInContext:(id)_ctx {
40 This returns the names of the children of a collection.
41 Could return toOneRelationshipKeys+toManyRelationshipKeys ?
43 NSClassDescription *cd;
45 if ((cd = [self soClassDescription]))
46 return [[cd toOneRelationshipKeys] objectEnumerator];
48 return [[self toOneRelationshipKeys] objectEnumerator];
51 - (EODataSource *)contentDataSourceInContext:(id)_ctx {
52 return [[[SoObjectDataSource alloc] initWithObject:self
53 inContext:_ctx] autorelease];
56 - (EODataSource *)davFlatDataSourceInContext:(id)_ctx {
58 @"%s: this method is deprecated,use -contentDataSourceInContext: !"];
59 return [self contentDataSourceInContext:_ctx];
62 - (NSArray *)davQueryOnSelf:(EOFetchSpecification *)_fs inContext:(id)_ctx {
63 id<EOQualifierEvaluation> q;
67 if ((q = (void *)[_fs qualifier])) {
68 if (![q evaluateWithObject:self]) {
69 [self debugWithFormat:@" self doesn't match qualifier."];
70 return [NSArray array];
74 if ((keys = [_fs selectedWebDAVPropertyNames]) == nil) {
76 Note: this shouldn't happen anymore, a default-set will be used by
79 keys = [[self soClassDescription] attributeKeys];
80 [self debugWithFormat:@"using keys from description: %@", keys];
83 /* ensure that the URL is added */
84 keys = [keys arrayByAddingObject:@"davURL"];
86 if ([_fs queryWebDAVPropertyNamesOnly]) {
87 /* how does the renderer know, that these are the keys ? */
88 [self debugWithFormat:@"deliver keys only: %@", keys];
89 return [NSArray arrayWithObject:keys];
92 if ((values = [self valuesForKeys:keys]) == nil)
95 return [NSArray arrayWithObject:values];
98 - (id)performWebDAVDeepQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
99 /* this just does a flat search :-(, maybe we should return 403 ? */
100 WEClientCapabilities *cc;
104 BOOL includeSelf, doDeep;
107 /* setup scope info */
109 scope = [_fs scopeOfWebDAVQuery];
110 includeSelf = [scope rangeOfString:@"-self"].length == 0 ? NO : YES;
113 /* do some user-agent specific tolerance */
115 cc = [[(id <WOPageGenerationContext>)_ctx request] clientCapabilities];
119 ua = [cc userAgentType];
120 if ([ua isEqualToString:@"Evolution"] || [ua isEqualToString:@"WebFolder"])
123 [self logWithFormat:@"return self on UA: %@", ua];
129 /* perform deep query */
131 ds = [self contentDataSourceInContext:_ctx];
132 [ds setFetchSpecification:_fs];
134 if ((result = [ds fetchObjects]) == nil)
138 if ((count = [result count]) == 0) {
140 return [self davQueryOnSelf:_fs inContext:_ctx];
145 ma = [NSMutableArray arrayWithCapacity:(count + 2)];
148 [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
150 /* add flat results */
151 [ma addObjectsFromArray:result];
155 Should walk over each result and reperform the query with deep-self.
156 If the results came from SoObjectDataSource this is possible because
157 the "full" object is none in the SoObjectResultEntry.
160 @"WARNING: attempted deep-search, not supported yet."];
167 - (id)performWebDAVBulkQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
168 NSAutoreleasePool *pool;
169 EOFetchSpecification *subSpec;
170 NSMutableArray *results;
174 pool = [[NSAutoreleasePool alloc] init];
175 //[self debugWithFormat:@"perform bulk query ..."];
177 /* create a sub-fetch-spec */
179 NSMutableDictionary *hints;
181 hints = [[_fs hints] mutableCopy];
182 [hints removeObjectForKey:@"bulkTargetKeys"];
184 subSpec = [[_fs copy] autorelease];
185 [subSpec setHints:hints];
189 results = [NSMutableArray arrayWithCapacity:256];
190 keys = [[_fs davBulkTargetKeys] objectEnumerator];
191 while ((key = [keys nextObject])) {
196 [self debugWithFormat:@" check bulk key: '%@'", key];
200 if ([key rangeOfString:@"/"].length == 0) {
201 /* simple key, just use -lookupName */
202 child = [self lookupName:key inContext:_ctx acquire:NO];
204 [self logWithFormat:@"ERROR: did not find the BPROPFIND target '%@'",
210 /* complex key, try to traverse */
211 // TODO: pass auth parameters to traversal context !!
212 child = [self traversePath:key acquire:NO];
215 @"ERROR: did not find the BPROPFIND target '%@' by traversing.",
219 if ([child isKindOfClass:[NSException class]]) {
220 [self logWithFormat:@"traversing bulk path '%@', failed: %@",
224 [self logWithFormat:@"traversed bulk path '%@', got: %@", key, child];
227 /* set entity name */
228 [subSpec setEntityName:
229 [[_fs entityName] stringByAppendingPathComponent:key]];
231 /* perform subquery */
232 childResults = [child performWebDAVQuery:subSpec inContext:_ctx];
234 if ([childResults isKindOfClass:[NSArray class]])
235 [results addObjectsFromArray:childResults];
237 [results addObject:childResults];
241 results = [results retain];
243 return [results autorelease];
246 - (id)performWebDAVQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
248 NSArray *bulkQueryKeys;
250 if (_fs == nil) return nil;
252 if ((bulkQueryKeys = [_fs davBulkTargetKeys]))
253 return [self performWebDAVBulkQuery:_fs inContext:_ctx];
255 scope = [_fs scopeOfWebDAVQuery];
256 if ([scope hasPrefix:@"flat"]) {
260 ds = [self contentDataSourceInContext:_ctx];
261 [ds setFetchSpecification:_fs];
262 if ((result = [ds fetchObjects]) == nil)
266 if ([scope rangeOfString:@"+self"].length > 0) {
267 /* should include self */
270 // TODO: don't add self if we work on ZideLook or WebFolders !
272 if ((len = [result count]) == 0)
273 result = [self davQueryOnSelf:_fs inContext:_ctx];
277 ma = [NSMutableArray arrayWithCapacity:(len + 2)];
278 [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
279 [ma addObjectsFromArray:result];
286 if ([scope hasPrefix:@"self"])
287 return [self davQueryOnSelf:_fs inContext:_ctx];
289 if ([scope hasPrefix:@"deep"])
290 return [self performWebDAVDeepQuery:_fs inContext:_ctx];
292 [self logWithFormat:@"ERROR: called with invalid scope '%@'", scope];
296 @end /* NSObject(SoObjectDAVQueries) */