]> err.no Git - sope/blob - sope-gdl1/GDLAccess/EOAdaptor.m
added missing inline pathes
[sope] / sope-gdl1 / GDLAccess / EOAdaptor.m
1 /* 
2    EOAttributeOrdering.m
3
4    Copyright (C) 1996 Free Software Foundation, Inc.
5
6    Author: Ovidiu Predescu <ovidiu@bx.logicnet.ro>
7    Date: 1996
8
9    This file is part of the GNUstep Database Library.
10
11    This library is free software; you can redistribute it and/or
12    modify it under the terms of the GNU Library General Public
13    License as published by the Free Software Foundation; either
14    version 2 of the License, or (at your option) any later version.
15
16    This library is distributed in the hope that it will be useful,
17    but WITHOUT ANY WARRANTY; without even the implied warranty of
18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19    Library General Public License for more details.
20
21    You should have received a copy of the GNU Library General Public
22    License along with this library; see the file COPYING.LIB.
23    If not, write to the Free Software Foundation,
24    59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 #include "EOAdaptor.h"
28 #include "EOAdaptorChannel.h"
29 #include "EOAdaptorContext.h"
30 #include "EOAttribute.h"
31 #include "EOFExceptions.h"
32 #include "EOModel.h"
33 #include "EOSQLExpression.h"
34 #include "common.h"
35
36 @implementation EOAdaptor
37
38 + (id)adaptorWithModel:(EOModel*)_model {
39     /* Check first to see if the adaptor class exists in the running program
40        by testing the existence of [_model adaptorClassName]. */
41     NSString *adaptorName = [_model adaptorName];
42     Class    adaptorClass = NSClassFromString([_model adaptorClassName]);
43     id       adaptor;
44
45     adaptor = adaptorClass
46         ? AUTORELEASE([[adaptorClass alloc] initWithName:adaptorName])
47         : [self adaptorWithName:adaptorName];
48     
49     [adaptor setModel:_model];
50     return adaptor;
51 }
52
53 + (NSArray *)adaptorSearchPathes {
54   // TODO: add support for Cocoa
55   static NSArray *searchPathes = nil;
56   NSDictionary   *env;
57   NSMutableArray *ma;
58   id             tmp;
59
60   if (searchPathes != nil) return searchPathes;
61
62   env = [[NSProcessInfo processInfo] environment];
63   ma  = [NSMutableArray arrayWithCapacity:8];
64   
65   if ((tmp = [env objectForKey:@"GNUSTEP_PATHPREFIX_LIST"]) == nil)
66     tmp = [env objectForKey:@"GNUSTEP_PATHLIST"];
67   tmp = [tmp componentsSeparatedByString:@":"];
68   if ([tmp count] > 0) {
69     NSEnumerator *e;
70     
71     e = [tmp objectEnumerator];
72     while ((tmp = [e nextObject])) {
73       if (![tmp hasSuffix:@"/"]) tmp = [tmp stringByAppendingString:@"/"];
74       
75       tmp = [tmp stringByAppendingFormat:@"Library/GDLAdaptors-%i.%i",
76                    GDL_MAJOR_VERSION, GDL_MINOR_VERSION];
77       
78       if ([ma containsObject:tmp] || tmp == nil) continue;
79       [ma addObject:tmp];
80     }
81   }
82   
83   tmp = [NSString stringWithFormat:@"/lib/sope-%i.%i/dbadaptors",
84                     SOPE_MAJOR_VERSION, SOPE_MINOR_VERSION];
85   [ma addObject:[@"/usr/local" stringByAppendingString:tmp]];
86   [ma addObject:[@"/usr" stringByAppendingString:tmp]];
87   
88   searchPathes = [ma copy];
89   if ([searchPathes count] == 0)
90     NSLog(@"%s: empty library search path !", __PRETTY_FUNCTION__);
91   return searchPathes;
92 }
93
94 + (id)adaptorWithName:(NSString *)adaptorName {
95   int      i, count;
96   NSBundle *bundle;
97   NSString *adaptorBundlePath = nil;
98   Class    adaptorClass       = Nil;
99   
100   bundle = [NSBundle mainBundle];
101     
102   /* Check error */
103   if ((adaptorName == nil) || [adaptorName isEqual:@""])
104     return nil;
105   
106   /* Look in application bundle */
107   bundle = [NSBundle mainBundle];
108   adaptorBundlePath =
109     [bundle pathForResource:adaptorName ofType:@"gdladaptor"];
110   
111   /* Look in standard paths */
112   if (adaptorBundlePath == nil) {
113     NSFileManager *fm;
114     NSString *dirname;
115     NSArray  *paths;
116       
117     fm      = [NSFileManager defaultManager];
118     paths   = [self adaptorSearchPathes];
119     dirname = [adaptorName stringByAppendingPathExtension:@"gdladaptor"];
120       
121     /* Loop through the paths and check each one */
122     for (i = 0, count = [paths count]; i < count; i++) {
123       NSString *p;
124       BOOL isDir;
125         
126       p = [[paths objectAtIndex:i] stringByAppendingPathComponent:dirname];
127       if (![fm fileExistsAtPath:p isDirectory:&isDir])
128         continue;
129       if (!isDir)
130         continue;
131         
132       adaptorBundlePath = p;
133       break;
134     }
135   }
136     
137   /* Make adaptor bundle */
138   bundle = adaptorBundlePath
139     ? [NSBundle bundleWithPath:adaptorBundlePath]
140     : nil;
141     
142   /* Check bundle */
143   if (bundle == nil) {
144     NSLog(@"EOAdaptor: cannot find adaptor bundle: '%@'", adaptorName);
145 #if 0
146     [[[[CannotFindAdaptorBundleException alloc]
147         initWithFormat:@"Cannot find adaptor bundle '%@'",
148         adaptorName] autorelease] raise];
149 #endif
150     return nil;
151   }
152
153   /* load bundle */
154
155   if (![bundle load]) {
156     NSLog(@"Cannot load adaptor bundle '%@'", adaptorName);
157 #if 1
158     [[[[InvalidAdaptorBundleException alloc]
159         initWithFormat:@"Cannot load adaptor bundle '%@'",
160         adaptorName] autorelease] raise];
161 #endif
162     return nil;
163   }
164     
165   /* Get the adaptor bundle "infoDictionary", and pricipal class, ie. the
166      adaptor class. Other info about the adaptor should be put in the
167      bundle's "Info.plist" file (property list format - see NSBundle class
168      documentation for details about reserved keys in this dictionary
169      property list containing one entry whose key is adaptorClassName. It
170      identifies the actual adaptor class from the bundle. */
171     
172   adaptorClass = [bundle principalClass];
173   if (adaptorClass == Nil) {
174     NSLog(@"The adaptor bundle '%@' at '%@' doesn't contain "
175           @"a principal class (infoDict=%@)",
176           adaptorName, [bundle bundlePath], [bundle infoDictionary]);
177       
178     [[[InvalidAdaptorBundleException alloc]
179        initWithFormat:@"The adaptor bundle '%@' doesn't contain "
180        @"a principal class (infoDict=%@)",
181        adaptorName, [bundle infoDictionary]]
182       raise];
183   }
184   return AUTORELEASE([[adaptorClass alloc] initWithName:adaptorName]);
185 }
186
187 + (NSString *)adaptorNameForURLScheme:(NSString *)_scheme {
188   // TODO: map scheme to adaptors (eg 'postgresql://' to PostgreSQL
189   
190   // TODO: hack in some known names
191   if ([_scheme isEqualToString:@"postgresql"]) return @"PostgreSQL";
192   if ([_scheme isEqualToString:@"sybase"])     return @"Sybase10";
193   if ([_scheme isEqualToString:@"sqlite"])     return @"SQLite3";
194
195   if ([_scheme isEqualToString:@"http"]) {
196     NSLog(@"WARNING(%s): asked for 'http' URL, "
197           @"please fix the URLs to 'postgresql'!",
198           __PRETTY_FUNCTION__);
199     return @"PostgreSQL";
200   }
201   
202   return _scheme;
203 }
204
205 - (NSDictionary *)connectionDictionaryForNSURL:(NSURL *)_url {
206   /*
207     "Database URLs"
208     
209     We use the schema:
210       postgresql://[user]:[password]@[host]:[port]/[dbname]/[tablename]
211   */
212   NSMutableDictionary *md;
213   id tmp;
214   
215   md = [NSMutableDictionary dictionaryWithCapacity:8];
216   
217   if ((tmp = [_url host]) != nil) 
218     [md setObject:tmp forKey:@"hostName"];
219   if ((tmp = [_url port]) != nil) 
220     [md setObject:tmp forKey:@"port"];
221   if ((tmp = [_url user]) != nil) 
222     [md setObject:tmp forKey:@"userName"];
223   if ((tmp = [_url password]) != nil) 
224     [md setObject:tmp forKey:@"password"];
225
226   /* extract dbname */
227   
228   tmp = [_url path];
229   if ([tmp hasPrefix:@"/"]) tmp = [tmp substringFromIndex:1];
230   if ([tmp length] > 0) {
231     NSRange r;
232     
233     r = [tmp rangeOfString:@"/"];
234     if (r.length > 0) tmp = [tmp substringToIndex:r.location];
235     
236     if ([tmp length] > 0)
237       [md setObject:tmp forKey:@"databaseName"];
238   }
239   
240   return md;
241 }
242
243 + (id)adaptorForNSURL:(NSURL *)_url {
244   EOAdaptor    *adaptor;
245   NSString     *adaptorName;
246   NSDictionary *condict;
247   
248   if (_url == nil)
249     return nil;
250   
251   adaptorName = [self adaptorNameForURLScheme:[_url scheme]];
252   adaptor     = [self adaptorWithName:adaptorName];
253   
254   if ((condict = [adaptor connectionDictionaryForNSURL:_url]) != nil)
255     [adaptor setConnectionDictionary:condict];
256   
257   return adaptor;
258 }
259
260 + (id)adaptorForURL:(id)_url {
261   NSURL *url;
262   
263   if (_url == nil)
264     return nil;
265   
266   if ([_url isKindOfClass:[NSURL class]])
267     url = _url;
268   else if ((url = [NSURL URLWithString:[_url stringValue]]) == nil) {
269     NSLog(@"ERROR(%s): could not parse URL: '%@'", __PRETTY_FUNCTION__, _url);
270     return nil;
271   }
272   
273   return [self adaptorForNSURL:url];
274 }
275
276 - (id)initWithName:(NSString*)_name {
277     ASSIGN(self->name, _name);
278     self->contexts = [[NSMutableArray allocWithZone:[self zone]] init];
279     return self;
280 }
281
282 - (void)dealloc {
283     RELEASE(self->model);
284     RELEASE(self->name);
285     RELEASE(self->connectionDictionary);
286     RELEASE(self->pkeyGeneratorDictionary);
287     RELEASE(self->contexts);
288     [super dealloc];
289 }
290
291 /* accessors */
292
293 - (void)setConnectionDictionary:(NSDictionary*)_dictionary {
294   if([self hasOpenChannels]) {
295     [NSException raise:NSInvalidArgumentException
296                  format:@"Cannot set the connection dictionary "
297                  @"while the adaptor is connected!"];
298   }
299   ASSIGN(self->connectionDictionary, _dictionary);
300   [self->model setConnectionDictionary:_dictionary];
301 }
302 - (NSDictionary *)connectionDictionary {
303   return self->connectionDictionary;
304 }
305 - (BOOL)hasValidConnectionDictionary {
306   return NO;
307 }
308
309 - (EOAdaptorContext*)createAdaptorContext {
310   return AUTORELEASE([[[self adaptorContextClass] alloc] 
311                              initWithAdaptor:self]);
312 }
313 - (NSArray *)contexts {
314   NSMutableArray *ma;
315   unsigned i, count;
316   
317   if ((count = [self->contexts count]) == 0)
318     return nil;
319
320   ma = [NSMutableArray arrayWithCapacity:count];
321   for (i = 0; i < count; i++)
322     [ma addObject:[[self->contexts objectAtIndex:i] nonretainedObjectValue]];
323   
324   return ma;
325 }
326
327 /* Setting pkey generation info */
328
329 - (void)setPkeyGeneratorDictionary:(NSDictionary*)aDictionary {
330   ASSIGN(self->pkeyGeneratorDictionary, aDictionary);
331   [self->model setPkeyGeneratorDictionary:aDictionary];
332 }
333 - (NSDictionary*)pkeyGeneratorDictionary {
334   return self->pkeyGeneratorDictionary;
335 }
336
337 // notifications
338
339 - (void)contextDidInit:aContext {
340     [self->contexts addObject:[NSValue valueWithNonretainedObject:aContext]];
341 }
342
343 - (void)contextWillDealloc:aContext {
344     int i;
345     
346     for (i = [contexts count]-1; i >= 0; i--) {
347         if ([[contexts objectAtIndex:i] nonretainedObjectValue] == aContext) {
348             [contexts removeObjectAtIndex:i];
349             break;
350         }
351     }
352 }
353
354 - (BOOL)hasOpenChannels {
355     int i;
356
357     for (i = [contexts count] - 1; i >= 0; i--) {
358         EOAdaptorContext* ctx = [[contexts objectAtIndex:i] 
359             nonretainedObjectValue];
360         if ([ctx hasOpenChannels])
361             return YES;
362     }
363     return NO;
364 }
365
366 - (id)formatAttribute:(EOAttribute *)_attribute {
367     return [_attribute expressionValueForContext:nil];
368 }
369
370 - (id)formatValue:(id)_value forAttribute:(EOAttribute *)attribute {
371   if (_value == nil) _value = [NSNull null];
372   return [_value expressionValueForContext:nil];
373 }
374
375 - (void)reportError:(NSString*)error {
376     if(delegateWillReportError) {
377         if([delegate adaptor:self willReportError:error] == NO)
378             return;
379     }
380     NSLog(@"%@ adaptor error: %@", name, error);
381 }
382
383 - (void)setDelegate:(id)_delegate {
384     self->delegate = _delegate;
385     self->delegateWillReportError
386         = [self->delegate respondsToSelector:
387                             @selector(adaptor:willReportError:)];
388 }
389
390 - (void)setModel:(EOModel *)_model {
391     ASSIGN(self->model, _model);
392     [self setConnectionDictionary:[_model connectionDictionary]];
393     [self setPkeyGeneratorDictionary:[_model pkeyGeneratorDictionary]];
394 }
395 - (EOModel *)model {
396     return self->model;
397 }
398
399 - (NSString *)name {
400     return self->name;
401 }
402
403 - (Class)expressionClass {
404   return [EOSQLExpression class];
405 }
406 - (Class)adaptorContextClass {
407   return [EOAdaptorContext class];
408 }
409 - (Class)adaptorChannelClass {
410   return [EOAdaptorChannel class];
411 }
412
413 - (BOOL)attributeAllowedInDistinctSelects:(EOAttribute *)_attr {
414   return YES;
415 }
416 - (BOOL)isValidQualifierType:(NSString*)typeName {
417   return NO;
418 }
419 - (id)delegate {
420   return self->delegate;
421 }
422
423 // description
424
425 - (NSString *)description {
426   return [NSString stringWithFormat:
427                      @"<%@[0x%08X]: name=%@ "
428                      @"model=%s connection-dict=%s>",
429                      NSStringFromClass([self class]), self,
430                      [self name],
431                      [self model] ? "yes" : "no",
432                      [self connectionDictionary] ? "yes" : "no"];
433 }
434
435 @end /* EOAdaptor */
436
437 @implementation EOAdaptor(EOF2Additions)
438
439 - (BOOL)canServiceModel:(EOModel *)_model {
440   return YES;
441 }
442
443 @end