]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WebDAV/SoObject+SoDAVQuery.m
renamed packages as discussed in the developer list
[sope] / sope-appserver / NGObjWeb / WebDAV / SoObject+SoDAVQuery.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "SoObject+SoDAV.h"
24 #include "SoObject.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>
32 #include "common.h"
33
34 @implementation NSObject(SoObjectDAVQueries)
35
36 static int debugBulk = NO; // TODO: set to -1 and use defaults
37
38 - (NSEnumerator *)davChildKeysInContext:(id)_ctx {
39   /*
40     This returns the names of the children of a collection.
41     Could return toOneRelationshipKeys+toManyRelationshipKeys ? 
42   */
43   NSClassDescription *cd;
44   
45   if ((cd = [self soClassDescription]))
46     return [[cd toOneRelationshipKeys] objectEnumerator];
47   
48   return [[self toOneRelationshipKeys] objectEnumerator];
49 }
50
51 - (EODataSource *)contentDataSourceInContext:(id)_ctx {
52   return [[[SoObjectDataSource alloc] initWithObject:self
53                                       inContext:_ctx] autorelease];
54 }
55
56 - (EODataSource *)davFlatDataSourceInContext:(id)_ctx {
57   [self logWithFormat:
58           @"%s: this method is deprecated,use -contentDataSourceInContext: !"];
59   return [self contentDataSourceInContext:_ctx];
60 }
61
62 - (NSArray *)davQueryOnSelf:(EOFetchSpecification *)_fs inContext:(id)_ctx {
63   id<EOQualifierEvaluation> q;
64   NSDictionary *values;
65   NSArray *keys;
66   
67   if ((q = (void *)[_fs qualifier])) {
68     if (![q evaluateWithObject:self]) {
69       [self debugWithFormat:@"  self doesn't match qualifier."];
70       return [NSArray array];
71     }
72   }
73   
74   if ((keys = [_fs selectedWebDAVPropertyNames]) == nil) {
75     /*
76       Note: this shouldn't happen anymore, a default-set will be used by
77       the dispatcher.
78     */
79     keys = [[self soClassDescription] attributeKeys];
80     [self debugWithFormat:@"using keys from description: %@", keys];
81   }
82   
83   /* ensure that the URL is added */
84   keys = [keys arrayByAddingObject:@"davURL"];
85   
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];
90   }
91   
92   if ((values = [self valuesForKeys:keys]) == nil)
93     return nil;
94   
95   return [NSArray arrayWithObject:values];
96 }
97
98 - (id)performWebDAVDeepQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
99   /* this just does a flat search :-(, maybe we should return 403 ? */
100   WEClientCapabilities *cc;
101   EODataSource *ds;
102   NSArray      *result;
103   NSString *scope;
104   BOOL     includeSelf, doDeep;
105   unsigned count;
106   
107   /* setup scope info */
108   
109   scope = [_fs scopeOfWebDAVQuery];
110   includeSelf = [scope rangeOfString:@"-self"].length == 0 ? NO : YES;
111   doDeep      = YES;
112   
113   /* do some user-agent specific tolerance */
114   
115   cc = [[(id <WOPageGenerationContext>)_ctx request] clientCapabilities];
116   if (includeSelf) {
117     NSString *ua;
118     
119     ua = [cc userAgentType];
120     if ([ua isEqualToString:@"Evolution"] || [ua isEqualToString:@"WebFolder"])
121       includeSelf = NO;
122     else {
123       [self logWithFormat:@"return self on UA: %@", ua];
124       includeSelf = YES;
125     }
126   }
127   doDeep = NO;
128   
129   /* perform deep query */
130   
131   ds = [self contentDataSourceInContext:_ctx];
132   [ds setFetchSpecification:_fs];
133   
134   if ((result = [ds fetchObjects]) == nil)
135     /* nil is error */
136     return nil;
137   
138   if ((count = [result count]) == 0) {
139     if (includeSelf)
140       return [self davQueryOnSelf:_fs inContext:_ctx];
141   }
142   else {
143     NSMutableArray *ma;
144     
145     ma = [NSMutableArray arrayWithCapacity:(count + 2)];
146     
147     if (includeSelf)
148       [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
149     
150     /* add flat results */
151     [ma addObjectsFromArray:result];
152     
153     if (doDeep) {
154       /* 
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.
158       */
159       [self logWithFormat:
160               @"WARNING: attempted deep-search, not supported yet."];
161     }    
162     result = ma;
163   }
164   return result;
165 }
166
167 - (id)performWebDAVBulkQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
168   NSAutoreleasePool    *pool;
169   EOFetchSpecification *subSpec;
170   NSMutableArray *results;
171   NSEnumerator *keys;
172   NSString     *key;
173
174   pool = [[NSAutoreleasePool alloc] init];
175   //[self debugWithFormat:@"perform bulk query ..."];
176   
177   /* create a sub-fetch-spec */
178   {
179     NSMutableDictionary *hints;
180     
181     hints = [[_fs hints] mutableCopy];
182     [hints removeObjectForKey:@"bulkTargetKeys"];
183     
184     subSpec = [[_fs copy] autorelease];
185     [subSpec setHints:hints];
186     [hints release];
187   }
188   
189   results = [NSMutableArray arrayWithCapacity:256];
190   keys = [[_fs davBulkTargetKeys] objectEnumerator];
191   while ((key = [keys nextObject])) {
192     id child;
193     id childResults;
194     
195     if (debugBulk)
196       [self debugWithFormat:@"  check bulk key: '%@'", key];
197     
198     /* lookup target */
199     
200     if ([key rangeOfString:@"/"].length == 0) {
201       /* simple key, just use -lookupName */
202       child = [self lookupName:key inContext:_ctx acquire:NO];
203       if (child == nil) {
204         [self logWithFormat:@"ERROR: did not find the BPROPFIND target '%@'",
205                 key];
206         continue;
207       }
208     }
209     else {
210       /* complex key, try to traverse */
211       // TODO: pass auth parameters to traversal context !!
212       child = [self traversePath:key acquire:NO];
213       if (child == nil) {
214         [self logWithFormat:
215                 @"ERROR: did not find the BPROPFIND target '%@' by traversing.",
216                 key];
217         continue;
218       }
219       if ([child isKindOfClass:[NSException class]]) {
220         [self logWithFormat:@"traversing bulk path '%@', failed: %@", 
221                 key, child];
222         continue;
223       }
224       [self logWithFormat:@"traversed bulk path '%@', got: %@", key, child];
225     }
226     
227     /* set entity name */
228     [subSpec setEntityName:
229                [[_fs entityName] stringByAppendingPathComponent:key]];
230     
231     /* perform subquery */
232     childResults = [child performWebDAVQuery:subSpec inContext:_ctx];
233     if (childResults) {
234       if ([childResults isKindOfClass:[NSArray class]])
235         [results addObjectsFromArray:childResults];
236       else
237         [results addObject:childResults];
238     }
239   }
240   
241   results = [results retain];
242   [pool release];
243   return [results autorelease];
244 }
245
246 - (id)performWebDAVQuery:(EOFetchSpecification *)_fs inContext:(id)_ctx {
247   NSString *scope;
248   NSArray  *bulkQueryKeys;
249   
250   if (_fs == nil) return nil;
251
252   if ((bulkQueryKeys = [_fs davBulkTargetKeys]))
253     return [self performWebDAVBulkQuery:_fs inContext:_ctx];
254   
255   scope = [_fs scopeOfWebDAVQuery];
256   if ([scope hasPrefix:@"flat"]) {
257     EODataSource *ds;
258     NSArray *result;
259     
260     ds = [self contentDataSourceInContext:_ctx];
261     [ds setFetchSpecification:_fs];
262     if ((result = [ds fetchObjects]) == nil)
263       /* error */
264       return nil;
265     
266     if ([scope rangeOfString:@"+self"].length > 0) {
267       /* should include self */
268       unsigned len;
269       
270       // TODO: don't add self if we work on ZideLook or WebFolders !
271       
272       if ((len = [result count]) == 0)
273         result = [self davQueryOnSelf:_fs inContext:_ctx];
274       else {
275         NSMutableArray *ma;
276         
277         ma = [NSMutableArray arrayWithCapacity:(len + 2)];
278         [ma addObjectsFromArray:[self davQueryOnSelf:_fs inContext:_ctx]];
279         [ma addObjectsFromArray:result];
280         result = ma;
281       }
282     }
283     return result;
284   }
285
286   if ([scope hasPrefix:@"self"])
287     return [self davQueryOnSelf:_fs inContext:_ctx];
288   
289   if ([scope hasPrefix:@"deep"])
290     return [self performWebDAVDeepQuery:_fs inContext:_ctx];
291   
292   [self logWithFormat:@"ERROR: called with invalid scope '%@'", scope];
293   return nil;
294 }
295
296 @end /* NSObject(SoObjectDAVQueries) */