Browse code

eogenerator ported to MulleEOF

Nat! authored on 14/08/2015 16:26:08
Showing 147 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,115 @@
0
+/* EOAccessAdditions.h created by lindberg on Mon 20-Dec-1999 */
1
+
2
+#import <EOAccess/EOModel.h>
3
+#import <EOAccess/EOEntity.h>
4
+#import <EOAccess/EOAttribute.h>
5
+#import <EOAccess/EORelationship.h>
6
+#import <EOControl/EOFetchSpecification.h>
7
+#import "SystemType.h"
8
+
9
+/* EOAccess extension methods for use by templates */
10
+
11
+@interface EOModel (EOAccessAdditions)
12
+
13
+// Tries to find the framework name. First looks to see if a value for
14
+// "EOGeneratorFrameworkName" exists in the model's -userInfo dictionary, and if
15
+// not, looks at the model's -path to find the framework the .eomodeld is in.
16
+// Both PB.project files and path components ending in ".framework" are looked
17
+// for, so it should work for .eomodels insided installed frameworks or in a
18
+// development tree. If the framework name could not be found, returns nil.
19
+- (NSString *)frameworkName;
20
+
21
+// Uses isLike: to do the comparisons
22
+- (NSArray *)entityNamesMatchingWildcard:(NSString *)wildcard;
23
+
24
+@end
25
+
26
+@interface EOEntity (EOAccessAdditions)
27
+
28
+- (BOOL)hasParentEntity;
29
+- (NSString *)frameworkName;
30
+
31
+- (NSString *)objcImportString;
32
+- (NSString *)objcImportStringInRelationToEntity:(EOEntity *)sourceEntity;
33
+- (NSString *)parentObjCImportString;
34
+
35
+//uniqued array of relationships' -objcImportString
36
+- (NSArray *)referencedObjCImportStrings;
37
+- (NSArray *)arrayWithParentObjCImportStringIfNeeded;
38
+
39
+#ifdef EOF2_ONLY
40
+// Define for use by EOF2 systems
41
+- (NSString *)classNameWithoutPackage;
42
+- (NSArray *)fetchSpecificationNames;
43
+- (EOFetchSpecification *)fetchSpecificationNamed:(NSString *)name;
44
+#endif
45
+
46
+// Getting the Java package as a string
47
+- (NSString *)classPackageName;
48
+
49
+#ifndef EOF2_ONLY
50
+- (NSString *)clientClassPackageName;
51
+- (NSString *)javaParentClientClassName;
52
+
53
+// JavaClient methods... reimplementation of ones in EOJavaClientExtensions.EOMBundle
54
+- (NSArray *)clientClassAttributes;
55
+- (NSArray *)clientClassToOneRelationships;
56
+- (NSArray *)clientClassToManyRelationships;
57
+- (NSArray *)clientClassScalarAttributes;
58
+- (NSArray *)clientClassNonScalarAttributes;
59
+#endif
60
+
61
+- (NSArray *)fetchSpecifications;
62
+- (NSArray *)beautifiedFetchSpecificationDictionaries;
63
+- (NSArray *)javaBeautifiedFetchSpecificationDictionaries;
64
+
65
+@end
66
+
67
+#ifndef EOF2_ONLY
68
+// <EOJavaClient/EOAccessAdditions.h> isn't always there (the ObjC framework
69
+// does not come with WO 4.5.1 on OS X or with WO 5), so just declare the
70
+// methods here.  Except with WO 4.0, the methods are actually implemented
71
+// in the EOAccess framework, so this is OK.
72
+@interface EOEntity (JavaClientExtensions)
73
+- (NSString *)clientClassName;
74
+- (NSString *)clientClassNameWithoutPackage;
75
+- (NSString *)referenceClientClassName;
76
+- (NSArray *)clientClassProperties;
77
+- (NSArray *)clientClassPropertyAttributeNames;
78
+- (NSArray *)clientClassPropertyToOneRelationshipNames;
79
+- (NSArray *)clientClassPropertyToManyRelationshipNames;
80
+@end
81
+#endif
82
+
83
+@interface EORelationship (EOAccessAdditions)
84
+
85
+// If the destination entity is in an external framework, returns
86
+// <Framework/ClassName.h>, otherwise returns "ClassName.h".
87
+- (NSString *)objcImportString;
88
+
89
+@end
90
+
91
+@interface EOAttribute (EOAccessAdditions)
92
+
93
+- (NSString *)javaValueTypeClassName;
94
+- (NSString *)javaScalarValueTypeClassName;
95
+
96
+@end
97
+
98
+@interface EOFetchSpecification (EOAccessAdditions)
99
+
100
+- (NSArray *)bindingParametersIsJava:(BOOL)isJava;
101
+- (NSArray *)bindingParameters;
102
+- (NSArray *)javaBindingParameters;
103
+
104
+@end
105
+
106
+@interface NSString (ModelStringManipulations)
107
+
108
+- (NSString *)uppercaseUnderbarString;
109
+- (NSString *)lowercaseNonUnderbarString;
110
+
111
+@end
112
+
113
+@interface EOGeneratorAttributePoser : EOAttribute
114
+@end
0 115
new file mode 100644
... ...
@@ -0,0 +1,647 @@
0
+/* EOAccessAdditions.m created by lindberg on Mon 20-Dec-1999 */
1
+/*-
2
+ * Copyright (c) 2002-2006 Carl Lindberg, Mike Gentry, and Doug McClure
3
+ * All rights reserved.
4
+ *
5
+ * Redistribution and use in source and binary forms, with or without
6
+ * modification, are permitted provided that the following conditions
7
+ * are met:
8
+ * 1. Redistributions of source code must retain the above copyright
9
+ *    notice, this list of conditions and the following disclaimer.
10
+ * 2. Redistributions in binary form must reproduce the above copyright
11
+ *    notice, this list of conditions and the following disclaimer in the
12
+ *    documentation and/or other materials provided with the distribution.
13
+ *
14
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
15
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
18
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24
+ * POSSIBILITY OF SUCH DAMAGE.
25
+ */
26
+
27
+#import "EOAccessAdditions.h"
28
+#import "FoundationAdditions.h"
29
+#import <Foundation/Foundation.h>
30
+//#import <EOModeler/EOModelExtensions.h>
31
+
32
+#ifdef EOF2_ONLY
33
+@interface EOQualifier (EOF2AccessAdditions)
34
+- (NSArray *)bindingKeys;
35
+- (NSString *)keyPathForBindingKey:(NSString *)key;
36
+@end
37
+@interface EOEntity (JavaExtensions)
38
+- (NSString *)referenceJavaClassName;
39
+@end
40
+@interface EOAttribute (JavaExtensions)
41
+- (NSString *)javaValueClassName;
42
+@end
43
+@implementation EOQualifier (EOF2AccessAdditions)
44
+- (NSArray *)bindingKeys { return [NSArray array]; }
45
+- (NSString *)keyPathForBindingKey:(NSString *)key { return nil; }
46
+@end
47
+#endif
48
+
49
+@implementation EOModel (EOAccessAdditions)
50
+
51
+/*"
52
+ * Tries to find the framework name. First looks to see if a value for
53
+ * "EOGeneratorFrameworkName" exists in the model's -userInfo dictionary, and if
54
+ * not, looks at the model's -path to find the framework the .eomodeld is in.
55
+ * Both PB.project files and path components ending in ".framework" are looked
56
+ * for, so it should work for .eomodels insided installed frameworks or in a
57
+ * development tree. If the framework name could not be found, returns nil.
58
+ * Several other custom methods use this information to generate \#import
59
+ * statements better. If all your EO classes are in the same framework, this
60
+ * doesn't make much difference, but if there are EOModels in several different
61
+ * frameworks with interrelationships, these methods can make life a lot easier.
62
+"*/
63
+- (NSString *)frameworkName
64
+{
65
+    NSDictionary  *userInfo = [self userInfo];
66
+    NSFileManager *manager  = [NSFileManager defaultManager];
67
+    NSString      *name;
68
+
69
+    name = [userInfo objectForKey:@"EOGeneratorFrameworkName"];
70
+
71
+    if (name == nil)
72
+    {
73
+        NSString *fullPath = [self path];
74
+        NSMutableDictionary *mutableInfo = [[userInfo mutableCopy] autorelease];
75
+
76
+        if (mutableInfo == nil) mutableInfo = [NSMutableDictionary dictionary];
77
+
78
+        if (fullPath != nil && ![fullPath isAbsolutePath])
79
+            fullPath = [[manager currentDirectoryPath] stringByAppendingPathComponent:fullPath];
80
+
81
+        while ([fullPath isAbsolutePath])
82
+        {
83
+            NSString *pbPath;
84
+
85
+            fullPath = [fullPath stringByDeletingLastPathComponent];
86
+            pbPath = [fullPath stringByAppendingPathComponent:@"PB.project"];
87
+
88
+            if ([manager regularFileExistsAtPath:pbPath])
89
+            {
90
+                NSDictionary *project = [NSDictionary dictionaryWithContentsOfFile:pbPath];
91
+
92
+                if ([[project objectForKey:@"PROJECTTYPE"] hasSuffix:@"Framework"])
93
+                {
94
+                    name = [project objectForKey:@"PROJECTNAME"];
95
+                    break;
96
+                }
97
+            }
98
+            else if ([[fullPath pathExtension] isEqual:@"framework"])
99
+            {
100
+                name = [[fullPath lastPathComponent] stringByDeletingPathExtension];
101
+                break;
102
+            }
103
+        }
104
+
105
+        [mutableInfo setObject:name? name : @"" forKey:@"EOGeneratorFrameworkName"];
106
+        [self setUserInfo:mutableInfo];
107
+    }
108
+
109
+    return [name length] > 0 ? name : nil;
110
+}
111
+
112
+- (NSArray *)entityNamesMatchingWildcard:(NSString *)wildcard
113
+{
114
+    NSMutableArray *names = [NSMutableArray array];
115
+    NSArray *entities = [self entities];
116
+    int i, count = [entities count];
117
+
118
+    for (i=0; i<count; i++)
119
+    {
120
+        NSString *entityName = [(EOEntity*)[entities objectAtIndex:i] name];
121
+        if ([entityName isLike:wildcard])
122
+            [names addObject:entityName];
123
+    }
124
+
125
+    return names;
126
+}
127
+
128
+@end
129
+
130
+
131
+@implementation EOEntity (EOAccessAdditions)
132
+
133
+/*" Returns YES/NO if the there is a parent entity for this EOEntity. "*/
134
+- (BOOL)hasParentEntity
135
+{
136
+    return ([self parentEntity] != nil);
137
+}
138
+
139
+/*" Returns the framework name that the model is in. "*/
140
+- (NSString *)frameworkName
141
+{
142
+    return [[self model] frameworkName];
143
+}
144
+
145
+/*"
146
+ * Returns <Framework/ClassName.h> if inside a framework, "ClassName.h"
147
+ * otherwise.
148
+"*/
149
+- (NSString *)objcImportString
150
+{
151
+    return [self objcImportStringInRelationToEntity:nil];
152
+}
153
+
154
+/*"
155
+ * If sourceEntity is nil, returns <Framework/ClassName.h> if inside a
156
+ * framework, "ClassName.h" otherwise. If sourceEntity is non-nil, the
157
+ * <Framework/ClassName.h> version will only be returned if the receiver's
158
+ * framework and sourceEntity's framework are different.  This depends on
159
+ * the -#frameworkName method doing the right thing.
160
+"*/
161
+- (NSString *)objcImportStringInRelationToEntity:(EOEntity *)sourceEntity
162
+{
163
+    NSString *myClass = [self className];
164
+    NSString *myFramework = [self frameworkName];
165
+    NSString *sourceFramework = [sourceEntity frameworkName];
166
+
167
+    if ([myClass hasSuffix:@"EOGenericRecord"]) return nil;
168
+
169
+    if (myFramework != nil &&
170
+        (sourceEntity == nil || ![sourceFramework isEqualToString:myFramework]))
171
+    {
172
+        return [NSString stringWithFormat:@"<%@/%@.h>", myFramework, myClass];
173
+    }
174
+    else
175
+    {
176
+        return [NSString stringWithFormat:@"\"%@.h\"", myClass];
177
+    }
178
+}
179
+
180
+/*"
181
+ * If there is no parent entity, returns nil. Otherwise, uses
182
+ * -#objcImportStringInRelationToEntity: to determine the string needed to
183
+ * \#import the parent class. I'm not sure if EOModeler lets you have the parent
184
+ * entity in an external .eomodeld, but we'll provide this to be safe.
185
+"*/
186
+- (NSString *)parentObjCImportString
187
+{
188
+    return [[self parentEntity] objcImportStringInRelationToEntity:self];
189
+}
190
+
191
+/*"
192
+ * If -#parentObjCImportString is nil, returns an empty array, otherwise returns
193
+ * a single-element array with the parent import string.
194
+"*/
195
+- (NSArray *)arrayWithParentObjCImportStringIfNeeded
196
+{
197
+    NSString *import = [self parentObjCImportString];
198
+
199
+    if (import != nil)
200
+        return [NSArray arrayWithObject:import];
201
+    else
202
+        return [NSArray array];
203
+}
204
+
205
+/*"
206
+ * A parallel for -#referencedClassNames for dealing with import strings. The
207
+ * array will contain a uniqued list of \#import strings for all related
208
+ * entities.
209
+"*/
210
+- (NSArray *)referencedObjCImportStrings
211
+{
212
+    NSArray        *relationships = [self relationships];
213
+    int            i, count = [relationships count];
214
+    NSMutableArray *refImports = [NSMutableArray arrayWithCapacity:count];
215
+
216
+    for (i=0; i<count; i++)
217
+    {
218
+        EORelationship *relationship = [relationships objectAtIndex:i];
219
+        EOEntity       *destEntity   = [relationship destinationEntity];
220
+
221
+        if (![[destEntity className] hasSuffix:@"EOGenericRecord"])
222
+        {
223
+            NSString *import = [relationship objcImportString];
224
+            if (import && ![refImports containsObject:import])
225
+                [refImports addObject:import];
226
+        }
227
+    }
228
+
229
+    return [refImports sortedArrayUsingSelector:@selector(compare:)];
230
+}
231
+
232
+
233
+- (NSString *)classPackageName
234
+{
235
+    NSString *className = [self className];
236
+    NSRange  dotRange = [className rangeOfString:@"." options:NSBackwardsSearch];
237
+
238
+    if (dotRange.length > 0)
239
+        return [className substringToIndex:dotRange.location];
240
+
241
+    return nil;
242
+}
243
+
244
+#ifndef EOF2_ONLY
245
+- (NSString *)clientClassPackageName
246
+{
247
+    NSString *className = [self clientClassName];
248
+    NSRange  dotRange = [className rangeOfString:@"." options:NSBackwardsSearch];
249
+
250
+    if (dotRange.length > 0)
251
+        return [className substringToIndex:dotRange.location];
252
+
253
+    return nil;
254
+}
255
+
256
+- (NSString *)javaParentClientClassName
257
+{
258
+    NSString *parentClass = [[self parentEntity] clientClassName];
259
+    if (parentClass == nil || [parentClass length] == 0)
260
+        parentClass = @"EOGenericRecord";
261
+    return parentClass;
262
+}
263
+
264
+/*
265
+ * Implementations for some JavaClient-specific methods that EOModeler gets
266
+ * because they are in the EOJavaClientExtensions.EOMBundle. We could possibly
267
+ * load the bundle, but this is easier.
268
+ */
269
+
270
+- (NSArray *)clientClassAttributes
271
+{
272
+    NSArray *names = [self clientClassPropertyAttributeNames];
273
+    int     i, count = [names count];
274
+    NSMutableArray *attributes = [NSMutableArray arrayWithCapacity:count];
275
+
276
+    for (i=0; i<count; i++)
277
+        [attributes addObject:[self attributeNamed:[names objectAtIndex:i]]];
278
+
279
+    return attributes;
280
+}
281
+
282
+- (NSArray *)clientClassToOneRelationships
283
+{
284
+    NSArray *names = [self clientClassPropertyToOneRelationshipNames];
285
+    int     i, count = [names count];
286
+    NSMutableArray *relationships = [NSMutableArray arrayWithCapacity:count];
287
+
288
+    for (i=0; i<count; i++)
289
+        [relationships addObject:[self relationshipNamed:[names objectAtIndex:i]]];
290
+
291
+    return relationships;
292
+}
293
+
294
+- (NSArray *)clientClassToManyRelationships
295
+{
296
+    NSArray *names = [self clientClassPropertyToManyRelationshipNames];
297
+    int     i, count = [names count];
298
+    NSMutableArray *relationships = [NSMutableArray arrayWithCapacity:count];
299
+
300
+    for (i=0; i<count; i++)
301
+        [relationships addObject:[self relationshipNamed:[names objectAtIndex:i]]];
302
+
303
+    return relationships;
304
+}
305
+
306
+// These next two aren't used, but the bundle implements them, so we might as
307
+// well too in case someone wants to use them.
308
+- (NSArray *)clientClassScalarAttributes
309
+{
310
+    NSArray *attributes = [self clientClassAttributes];
311
+    int     i, count = [attributes count];
312
+    NSMutableArray *scalars = [NSMutableArray arrayWithCapacity:count];
313
+
314
+    for (i=0; i<count; i++)
315
+    {
316
+        EOAttribute *attrib = [attributes objectAtIndex:i];
317
+        if ([attrib isScalar])
318
+            [scalars addObject:attrib];
319
+    }
320
+
321
+    return scalars;
322
+}
323
+
324
+- (NSArray *)clientClassNonScalarAttributes
325
+{
326
+    NSArray *attributes = [self clientClassAttributes];
327
+    int     i, count = [attributes count];
328
+    NSMutableArray *nonscalars = [NSMutableArray arrayWithCapacity:count];
329
+
330
+    for (i=0; i<count; i++)
331
+    {
332
+        EOAttribute *attrib = [attributes objectAtIndex:i];
333
+        if (![attrib isScalar])
334
+            [nonscalars addObject:attrib];
335
+    }
336
+
337
+    return nonscalars;
338
+}
339
+
340
+#endif
341
+
342
+#ifdef EOF2_ONLY
343
+/* Define for use by EOF2 systems */
344
+- (NSString *)classNameWithoutPackage
345
+{
346
+    NSString *className = [self className];
347
+    NSRange  dotRange = [className rangeOfString:@"." options:NSBackwardsSearch];
348
+
349
+    if (dotRange.length > 0)
350
+        className = [className substringFromIndex:NSMaxRange(dotRange)];
351
+
352
+    return className;
353
+}
354
+
355
+- (NSString *)referenceJavaClassName
356
+{
357
+    return [self className];
358
+}
359
+
360
+- (NSArray *)fetchSpecificationNames
361
+{
362
+    return [NSArray array];
363
+}
364
+- (EOFetchSpecification *)fetchSpecificationNamed:(NSString *)name
365
+{
366
+    return nil;
367
+}
368
+- (NSArray *)clientClassProperties
369
+{
370
+    return [NSArray array];
371
+}
372
+
373
+#endif
374
+
375
+- (NSArray *)fetchSpecifications
376
+{
377
+    NSArray *fetchSpecificationNames = [self fetchSpecificationNames];
378
+    NSMutableArray *fetchSpecifications = [NSMutableArray arrayWithCapacity:[fetchSpecificationNames count]];
379
+    NSEnumerator *fetchNameEnumerator = [fetchSpecificationNames objectEnumerator];
380
+    NSString *fetchName;
381
+
382
+    while ( fetchName = [fetchNameEnumerator nextObject] ) {
383
+        NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
384
+        [dictionary setObject:fetchName forKey:@"name"];
385
+        [dictionary setObject:[self fetchSpecificationNamed:fetchName] forKey:@"spec"];
386
+        [dictionary setObject:[fetchName beautifyString] forKey:@"niceName"];
387
+        [fetchSpecifications addObject:dictionary];
388
+    }
389
+
390
+    return fetchSpecifications;
391
+}
392
+
393
+- (NSArray *)_beautifiedFetchSpecificationDictionariesIsJava:(BOOL)isJava
394
+{
395
+    NSArray *fetchSpecificationNames = [self fetchSpecificationNames];
396
+    NSMutableArray *fetchSpecifications = [NSMutableArray arrayWithCapacity:[fetchSpecificationNames count]];
397
+    NSMutableArray *addedNames = [NSMutableArray arrayWithCapacity:[fetchSpecificationNames count]];
398
+    NSEnumerator *fetchNameEnumerator = [fetchSpecificationNames objectEnumerator];
399
+    NSString *fetchName;
400
+
401
+    while ( fetchName = [fetchNameEnumerator nextObject] ) {
402
+        NSString *beautifyName = [fetchName beautifyString];
403
+        NSMutableString *methodName = [NSMutableString stringWithFormat:@"objectsFor%@", beautifyName];
404
+        EOFetchSpecification *fetchSpec = [self fetchSpecificationNamed:fetchName];
405
+        NSArray *bindings = [fetchSpec bindingParametersIsJava:isJava];
406
+        NSEnumerator *bindingEnumerator = [bindings objectEnumerator];
407
+        NSDictionary *binding;
408
+
409
+        if ( !isJava ) {
410
+            // To prevent duplicate method names, we must composite a complete ObjC name which will be
411
+            // the fetch specification name, beautified, and each of the bindings as a parameter
412
+            // ie: objectForFetchEmployees:departmentNumber:projectNumber:
413
+            [methodName appendString:@":"];
414
+
415
+            while ( binding = [bindingEnumerator nextObject] ) {
416
+                [methodName appendFormat:@"%@:", [binding objectForKey:@"name"]];
417
+            }
418
+        }
419
+        else {
420
+            // To prevent duplicate method names, we must composite a complete Java method name which will be
421
+            // the fetch specification name, beautified, and each binding's type as a parameter
422
+            // ie: objectForFetchEmployees(EOEditingContext,Department,Project)
423
+            [methodName appendString:@"(EOEditingContext"];
424
+
425
+            while ( binding = [bindingEnumerator nextObject] ) {
426
+                [methodName appendFormat:@",%@", [binding objectForKey:@"type"]];
427
+            }
428
+
429
+            [methodName appendString:@")"];
430
+        }
431
+
432
+        if ( [addedNames containsObject:methodName] ) {
433
+            ErrPrintf(@"Ignoring '%@' fetch specification in entity %@. Method name '%@' already used.", fetchName, [self name], methodName);
434
+        }
435
+        else {
436
+            NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
437
+            [dictionary setObject:methodName forKey:@"name"];
438
+            [dictionary setObject:fetchName forKey:@"fetchName"];
439
+            [dictionary setObject:beautifyName forKey:@"niceName"];
440
+            [dictionary setObject:fetchSpec forKey:@"fetchSpec"];
441
+            [dictionary setObject:bindings forKey:@"bindings"];
442
+            [fetchSpecifications addObject:dictionary];
443
+            [addedNames addObject:methodName];
444
+        }
445
+    }
446
+
447
+    return fetchSpecifications;
448
+}
449
+
450
+- (NSArray *)beautifiedFetchSpecificationDictionaries
451
+{
452
+    return [self _beautifiedFetchSpecificationDictionariesIsJava:NO];
453
+}
454
+
455
+- (NSArray *)javaBeautifiedFetchSpecificationDictionaries
456
+{
457
+    return [self _beautifiedFetchSpecificationDictionariesIsJava:YES];
458
+}
459
+
460
+@end
461
+
462
+
463
+// [PJYF June 3 2003]
464
+// Added this implemention to use the valueType in EOModeler for Java
465
+@implementation EOAttribute (EOAccessAdditions)
466
+
467
+- (NSString *)javaValueTypeClassName
468
+{
469
+    NSString *valueClassName = [self javaValueClassName];
470
+    NSString *valueType = [self valueType];
471
+
472
+    if ( [valueClassName isEqualToString:@"Number"] && ([valueType length] > 0) ) {
473
+        switch ( [valueType characterAtIndex:0] ) {
474
+            case 'b': return @"Byte";
475
+            case 's': return @"Short";
476
+            case 'i': return @"Integer";
477
+            case 'l': return @"Long";
478
+            case 'f': return @"Float";
479
+            case 'd': return @"Double";
480
+            case 'B': return @"java.math.BigDecimal";
481
+            case 'c': return @"Boolean";
482
+        }
483
+    }
484
+
485
+    return valueClassName;
486
+}
487
+
488
+- (NSString *)javaScalarValueTypeClassName
489
+{
490
+    NSString *valueClassName = [self javaValueClassName];
491
+    NSString *valueType = [self valueType];
492
+
493
+    if ( [valueClassName isEqualToString:@"Number"] && ([valueType length] > 0) ) {
494
+        switch ( [valueType characterAtIndex:0] ) {
495
+            case 'b': return @"byte";
496
+            case 's': return @"short";
497
+            case 'i': return @"int";
498
+            case 'l': return @"long";
499
+            case 'f': return @"float";
500
+            case 'd': return @"double";
501
+            case 'c': return @"boolean";
502
+        }
503
+    }
504
+
505
+    return nil;
506
+}
507
+
508
+@end
509
+
510
+
511
+@implementation EORelationship (EOAccessAdditions)
512
+
513
+- (NSString *)objcImportString
514
+{
515
+    return [[self destinationEntity] objcImportStringInRelationToEntity:[self entity]];
516
+}
517
+
518
+@end
519
+
520
+
521
+@implementation EOFetchSpecification (EOAccessAdditions)
522
+
523
+- (NSArray *)bindingParametersIsJava:(BOOL)forJava
524
+{
525
+    NSArray *bindings = [[self qualifier] bindingKeys];
526
+    EOClassDescription *classDesc = [EOClassDescription classDescriptionForEntityName:[self entityName]];
527
+    int i, count = [bindings count];
528
+    NSMutableArray *parameters = [NSMutableArray arrayWithCapacity:count];
529
+
530
+    for (i=0; i<count; i++)
531
+    {
532
+        NSString *binding = [bindings objectAtIndex:i];
533
+        NSString *keyPath = [[self qualifier] keyPathForBindingKey:binding];
534
+        EOClassDescription *currDesc = classDesc;
535
+        NSRange dotRange = [keyPath rangeOfString:@"."];
536
+        NSMutableDictionary *param = [NSMutableDictionary dictionary];
537
+
538
+        while (dotRange.length > 0)
539
+        {
540
+            currDesc = [currDesc classDescriptionForDestinationKey:[keyPath substringToIndex:dotRange.location]];
541
+            keyPath  = [keyPath substringFromIndex:NSMaxRange(dotRange)];
542
+            dotRange = [keyPath rangeOfString:@"."];
543
+        }
544
+
545
+        [param setObject:binding forKey:@"name"];
546
+        [param setObject:((forJava) ? @"java.lang.Object" : @"id") forKey:@"type"]; //set a default
547
+        [param setObject:((forJava) ? @"java.lang.Object " : @"id ") forKey:@"codeType"]; //set a default
548
+
549
+        if ([currDesc isKindOfClass:[EOEntityClassDescription class]])
550
+        {
551
+            EOEntity *entity = [(EOEntityClassDescription *)currDesc entity];
552
+
553
+            if ([entity attributeNamed:keyPath])
554
+            {
555
+                EOAttribute *attrib = [entity attributeNamed:keyPath];
556
+                NSString *type;
557
+
558
+                if (forJava) {
559
+                    type = [attrib javaValueClassName];
560
+                    [param setObject:type forKey:@"type"];
561
+                    [param setObject:[type stringByAppendingString:@" "] forKey:@"codeType"];
562
+                }
563
+                else {
564
+                    type = [attrib valueClassName];
565
+                    [param setObject:type forKey:@"type"];
566
+                    [param setObject:[type stringByAppendingString:@" *"] forKey:@"codeType"];
567
+                }
568
+
569
+                [param setObject:attrib forKey:@"attribute"];
570
+            }
571
+            else if ([entity relationshipNamed:keyPath])
572
+            {
573
+                EORelationship *rel = [entity relationshipNamed:keyPath];
574
+                NSString *type;
575
+
576
+                if (forJava) {
577
+                    type = [[rel destinationEntity] referenceJavaClassName];
578
+                    [param setObject:type forKey:@"type"];
579
+                    [param setObject:[type stringByAppendingString:@" "] forKey:@"codeType"];
580
+                }
581
+                else {
582
+                    type = [[rel destinationEntity] referenceClassName];
583
+                    [param setObject:[type substringToIndex:[type length]-2] forKey:@"type"]; // Removes the ' *' from the reference value type
584
+                    [param setObject:type forKey:@"codeType"];
585
+                }
586
+
587
+                [param setObject:rel forKey:@"relationship"];
588
+            }
589
+        }
590
+
591
+        [parameters addObject:param];
592
+    }
593
+
594
+    return parameters;
595
+}
596
+
597
+- (NSArray *)bindingParameters
598
+{
599
+    return [self bindingParametersIsJava:NO];
600
+}
601
+- (NSArray *)javaBindingParameters
602
+{
603
+    return [self bindingParametersIsJava:YES];
604
+}
605
+
606
+@end
607
+
608
+@implementation NSString (ModelStringManipulations)
609
+
610
+/*" Useful for turning key names into constant names "*/
611
+- (NSString *)uppercaseUnderbarString
612
+{
613
+    return [NSString externalNameForInternalName:self separatorString:@"_" useAllCaps:YES];
614
+}
615
+
616
+/*" Inverse of above method, just for completeness "*/
617
+- (NSString *)lowercaseNonUnderbarString
618
+{
619
+    return [NSString nameForExternalName:self separatorString:@"_" initialCaps:YES];
620
+}
621
+
622
+@end
623
+
624
+/*
625
+ * WO5 supports a valueType of "c" to juse java.lang.Boolean, but the
626
+ * javaValueClassName method still generates "Number".  We need to pose
627
+ * to fix this.
628
+ */
629
+@implementation EOGeneratorAttributePoser : EOAttribute
630
+- (NSString *)javaValueClassName
631
+{
632
+    if ([[self valueClassName] isEqual:@"NSNumber"] && [[self valueType] isEqual:@"c"])
633
+        return @"Boolean";
634
+    return [super javaValueClassName];
635
+}
636
+@end
637
+
638
+/* In WO5, some library that gets loaded looks for this class (it's in EOModeler).
639
+Not necessary but prevents an error from being printed out.
640
+*/
641
+@interface EOSchemaSynchronizationController : NSObject
642
+@end
643
+@implementation EOSchemaSynchronizationController
644
+@end
645
+
646
+
0 647
new file mode 100644
... ...
@@ -0,0 +1,310 @@
0
+<$comment
1
+EO Template for use by "eogenerator" based upon MiscMerge engine.
2
+You may customize this file to modify the templates generated
3
+by this tool.  See the MiscMerge documentation for a description
4
+of the parsing language.  The engine gets passed this file and an
5
+EOEntity to process, so the methods used must be ones that an
6
+EOEntity can respond to.
7
+
8
+BE SURE NOT TO INCLUDE DATES IN THIS FILE.  Since the "eogenerator"
9
+tool tries to compare the newly generated file with the old file,
10
+adding dates to this file will guarantee the old file gets
11
+overridden by the new file, forcing a recompilation of your EO.$>
12
+// <$GEN_PREFIX$><$classNameWithoutPackage$>.java
13
+// 
14
+// Created by eogenerator
15
+// DO NOT EDIT.  Make changes to <$classNameWithoutPackage$>.java instead.
16
+
17
+<$foreach package classPackage do$>package <$package$>;
18
+<$endforeach do$>
19
+import com.webobjects.foundation.*;
20
+import com.webobjects.eocontrol.*;
21
+import java.math.BigDecimal;
22
+import java.util.Enumeration;
23
+
24
+<$comment This is how to put in a custom EO superclass.  We also declare
25
+this class as being abstract, since it should never be instantiated.
26
+$>
27
+public abstract class <$GEN_PREFIX$><$classNameWithoutPackage$> extends <$if hasParentEntity$><$javaParentClassName$><$else$>MyEOSuperclass<$endif$>
28
+{
29
+<$comment
30
+
31
+Some people like to have constant strings defined for each key. For an
32
+attribute named fooBar, this will declare a FOO_BAR_KEY constant string,
33
+which can be used in calls to valueForKey(), addObjectToBothSides..., etc.
34
+A constant of ENTITY_NAME can be used for fetch specs and other methods.
35
+This lets the compiler flag usages of these keys when the names change.
36
+Additionally, it can be handy to have constants defined for the name 
37
+of the database table, the names of all the attribute column names, and fetch
38
+specifications.
39
+
40
+$>
41
+    public static final String ENTITY_NAME = "<$name$>";
42
+<$if externalName$>
43
+    public static final String ENTITY_TABLE_NAME = "<$externalName$>";<$endif$>
44
+<$foreach attribute attributes.@sortedNameArray do$>
45
+    public static final String <$attribute.name.uppercaseUnderbarString$>_KEY = "<$attribute.name$>";<$endforeach$>
46
+<$foreach attribute attributes.@sortedNameArray do$><$if attribute.columnName$>
47
+    public static final String <$attribute.name.uppercaseUnderbarString$>_COLKEY = "<$attribute.columnName$>";<$endif$><$endforeach$>
48
+<$foreach rel classToOneRelationships.@sortedNameArray do$>
49
+    public static final String <$rel.name.uppercaseUnderbarString$>_KEY = "<$rel.name$>";<$endforeach$>
50
+<$foreach rel classToManyRelationships.@sortedNameArray do$>
51
+    public static final String <$rel.name.uppercaseUnderbarString$>_KEY = "<$rel.name$>";<$endforeach$>
52
+<$foreach spec javaBeautifiedFetchSpecificationDictionaries.@sortedNameArray do$>
53
+    public static final String <$spec.fetchName.uppercaseUnderbarString$>_SPEC = "<$spec.fetchName$>";<$endforeach$>
54
+
55
+<$comment
56
+
57
+These do the same thing, but use mixed case strings instead of all uppercase.
58
+These are commented out by default
59
+
60
+    public static final String EntityName = "<$name$>";
61
+<$if externalName$>
62
+    public static final String EntityTableName = "<$externalName$>";<$endif$>
63
+<$foreach attribute attributes.@sortedNameArray do$>
64
+    public static final String <$attribute.name.initialCapitalString$>Key = "<$attribute.name$>";<$endforeach$>
65
+<$foreach attribute attributes.@sortedNameArray do$><$if attribute.columnName$>
66
+    public static final String <$attribute.name.initialCapitalString$>ColKey = "<$attribute.columnName$>";<$endif$><$endforeach$>
67
+<$foreach rel classToOneRelationships.@sortedNameArray do$>
68
+    public static final String <$rel.name.initialCapitalString$>Key = "<$rel.name$>";<$endforeach$>
69
+<$foreach rel classToManyRelationships.@sortedNameArray do$>
70
+    public static final String <$rel.name.initialCapitalString$>Key = "<$rel.name$>";<$endforeach$>
71
+<$foreach spec javaBeautifiedFetchSpecificationDictionaries.@sortedNameArray do$>
72
+    public static final String <$spec.fetchName.initialCapitalString$>Spec = "<$spec.fetchName$>";<$endforeach$>
73
+
74
+$><$comment
75
+
76
+This section will create a method to create a new instance of this entity.
77
+It is essentially identical to EOUtilies' createAndInsertInstance method.
78
+This won't necessarily work if you are using inheritance. The commented out
79
+method following this one would be generally a better method to use if
80
+you need to deal with inheritance.
81
+
82
+$><$if !isAbstractEntity$>
83
+    public static <$classNameWithoutPackage$> newInstance(EOEditingContext context) {
84
+    	EOClassDescription desc = EOClassDescription.classDescriptionForEntityName(ENTITY_NAME);
85
+    	EOEnterpriseObject object = desc.createInstanceWithEditingContext(context, null);
86
+    	context.insertObject(object);
87
+    	return (<$classNameWithoutPackage$>)object;
88
+    }<$endif$>
89
+<$comment Java does not allow static methods of the same name in a subclass
90
+   to return a different type, so for some types of inheritance the above will
91
+   not work.  In these cases, declare the method like this:
92
+
93
+    public static <$classNameWithoutPackage$> new<$classNameWithoutPackage$>Instance(EOEditingContext context)
94
+
95
+$>
96
+    public <$GEN_PREFIX$><$classNameWithoutPackage$>() {
97
+        super();
98
+    }
99
+
100
+<$comment
101
+Add methods to call named fetch specifications, with any qualifier bindings having typed
102
+parameters.
103
+
104
+$><$foreach FetchSpec javaBeautifiedFetchSpecificationDictionaries.@sortedNameArray do$>
105
+    public static NSArray objectsFor<$FetchSpec.niceName$>(EOEditingContext context<$foreach Binding FetchSpec.bindings do2$>, <$Binding.codeType$><$Binding.name$>Binding<$endforeach do2$>) {
106
+        EOFetchSpecification spec = EOFetchSpecification.fetchSpecificationNamed("<$FetchSpec.fetchName$>", "<$name$>");
107
+<$if FetchSpec.bindings.@count > 0$>
108
+        NSMutableDictionary bindings = new NSMutableDictionary();
109
+<$foreach Binding FetchSpec.bindings do2$>
110
+        if (<$Binding.name$>Binding != null)
111
+            bindings.setObjectForKey(<$Binding.name$>Binding, "<$Binding.name$>");<$endforeach do2$>
112
+        spec = spec.fetchSpecificationWithQualifierBindings(bindings);
113
+<$endif$>
114
+        return context.objectsWithFetchSpecification(spec);
115
+    }
116
+<$endforeach do$>
117
+
118
+<$foreach Attribute classAttributes.@sortedNameArray do$>
119
+    public <$Attribute.javaValueClassName$> <$Attribute.name$>() {
120
+        return (<$Attribute.javaValueClassName$>)storedValueForKey("<$Attribute.name$>");
121
+    }
122
+    public void set<$Attribute.name.initialCapitalString$>(<$Attribute.javaValueClassName$> aValue) {
123
+        takeStoredValueForKey(aValue, "<$Attribute.name$>");
124
+    }<$comment
125
+
126
+ADVANCED EXAMPLE
127
+
128
+The following code shows an example of using the userInfo dictionary on an attribute to create
129
+additional methods.
130
+
131
+This example allows the user to define the key 'abbreviate' to create a method that will turn a
132
+string into a abbreviated version.  This can be really handy in WO components where you may need
133
+to display a text string that could be very long, but need it to always fit in a certain area.
134
+Additional methods could be made to make shorter or longer abbreviated strings.  The code checks
135
+to see if the type of the attribute is a String and if the abbreviated length is at least greater
136
+than 3 characters, before it will create the method.
137
+
138
+<$if Attribute.javaValueClassName eq 'String' and Attribute.userInfo.abbreviate gt 3$>
139
+    public String abbreviated<$Attribute.name.initialCapitalString$>() {
140
+        String value = <$Attribute.name$>();
141
+        if ( value != null && value.length() > <$Attribute.userInfo.abbreviate$> )
142
+            value = value.substring(0,<$Attribute.userInfo.abbreviate$> - 3) + "...";
143
+        return value;
144
+    }
145
+<$endif$>
146
+
147
+This is just one example of data manipulation that eogenerator can do.  You could have methods that
148
+uppercase values, strip blanks, encrypt the text, etc. all determined by entries in the userInfo
149
+dictionary.  See below for a To-Many relationship example.
150
+
151
+$>
152
+<$endforeach do$>
153
+
154
+
155
+<$foreach ToOneRelationship classToOneRelationships.@sortedNameArray do$>
156
+    public <$ToOneRelationship.destinationEntity.referenceJavaClassName$> <$ToOneRelationship.name$>() {
157
+        return (<$ToOneRelationship.destinationEntity.referenceJavaClassName$>)storedValueForKey("<$ToOneRelationship.name$>");
158
+    }
159
+    public void set<$ToOneRelationship.name.initialCapitalString$>(<$ToOneRelationship.destinationEntity.referenceJavaClassName$> aValue) {
160
+        takeStoredValueForKey(aValue, "<$ToOneRelationship.name$>");
161
+    }<$comment
162
+
163
+The following method is better than using addObjectToBothSidesOfRelationshipWithKey directly
164
+because you will get compile time type checking instead of runtime checking (plus you don't
165
+risk typos in contstant strings of key names).
166
+$>
167
+    public void set<$ToOneRelationship.name.initialCapitalString$>Relationship(<$ToOneRelationship.destinationEntity.referenceJavaClassName$> value) {
168
+        if (value == null) {
169
+            <$ToOneRelationship.destinationEntity.referenceJavaClassName$> object = <$ToOneRelationship.name$>();
170
+            if (object != null)
171
+                removeObjectFromBothSidesOfRelationshipWithKey(object, "<$ToOneRelationship.name$>");
172
+        }
173
+        else {
174
+            addObjectToBothSidesOfRelationshipWithKey(value, "<$ToOneRelationship.name$>");
175
+        }
176
+    }
177
+<$endforeach do$>
178
+
179
+
180
+<$foreach ToManyRelationship classToManyRelationships.@sortedNameArray tomanyrels$>
181
+    public NSArray <$ToManyRelationship.name$>() {
182
+        return (NSArray)storedValueForKey("<$ToManyRelationship.name$>");
183
+    }
184
+    public void set<$ToManyRelationship.name.initialCapitalString$>(NSMutableArray aValue) {
185
+        takeStoredValueForKey(aValue, "<$ToManyRelationship.name$>");
186
+    }
187
+    public void addTo<$ToManyRelationship.name.initialCapitalString$>(<$ToManyRelationship.destinationEntity.referenceJavaClassName$> object) {
188
+        NSMutableArray array = (NSMutableArray)<$ToManyRelationship.name$>();
189
+        willChange();
190
+        array.addObject(object);
191
+    }
192
+    public void removeFrom<$ToManyRelationship.name.initialCapitalString$>(<$ToManyRelationship.destinationEntity.referenceJavaClassName$> object) {
193
+        NSMutableArray array = (NSMutableArray)<$ToManyRelationship.name$>();
194
+        willChange();
195
+        array.removeObject(object);
196
+    }<$comment
197
+
198
+The following adds typed methods to add or remove an object from a to-many relationship.
199
+This is better than using addObjectToBothSidesOfRelationshipWithKey directly because
200
+you will get compile time type checking instead of runtime checking, and you avoid the
201
+possibility of making a typo in the key name.
202
+$>
203
+    public void addTo<$ToManyRelationship.name.initialCapitalString$>Relationship(<$ToManyRelationship.destinationEntity.referenceJavaClassName$> object) {
204
+        addObjectToBothSidesOfRelationshipWithKey(object, "<$ToManyRelationship.name$>");
205
+    }
206
+    public void removeFrom<$ToManyRelationship.name.initialCapitalString$>Relationship(<$ToManyRelationship.destinationEntity.referenceJavaClassName$> object) {
207
+        removeObjectFromBothSidesOfRelationshipWithKey(object, "<$ToManyRelationship.name$>");
208
+    }<$comment
209
+
210
+The following adds typed methods to create, and delete objects from a to-many relationship.
211
+The main difference in the delete mechanism, versus the removeFrom... method above is that
212
+this delete method will remove the object from the editing context if it is we do not own
213
+its destination.  The user can override these methods in the subclass to provide additional
214
+functionality on these methods.
215
+$>
216
+    public <$ToManyRelationship.destinationEntity.referenceJavaClassName$> create<$ToManyRelationship.name.initialCapitalString$>Relationship() {
217
+	EOClassDescription eoClassDesc = EOClassDescription.classDescriptionForEntityName("<$ToManyRelationship.destinationEntity.name$>");
218
+	EOEnterpriseObject eoObject = eoClassDesc.createInstanceWithEditingContext(editingContext(), null);
219
+	editingContext().insertObject(eoObject);
220
+	addObjectToBothSidesOfRelationshipWithKey(eoObject, "<$ToManyRelationship.name$>");
221
+	return (<$ToManyRelationship.destinationEntity.referenceJavaClassName$>)eoObject;
222
+    }
223
+    public void delete<$ToManyRelationship.name.initialCapitalString$>Relationship(<$ToManyRelationship.destinationEntity.referenceJavaClassName$> object) {
224
+        removeObjectFromBothSidesOfRelationshipWithKey(object, "<$ToManyRelationship.name$>");<$
225
+if !ToManyRelationship.ownsDestination$>
226
+        editingContext().deleteObject(object);<$endif$>
227
+    }
228
+    public void deleteAll<$ToManyRelationship.name.initialCapitalString$>Relationships() {
229
+	Enumeration objects = new NSArray(<$ToManyRelationship.name$>()).objectEnumerator();
230
+	while ( objects.hasMoreElements() )
231
+	    delete<$ToManyRelationship.name.initialCapitalString$>Relationship((<$ToManyRelationship.destinationEntity.referenceJavaClassName$>)objects.nextElement());
232
+    }<$comment
233
+
234
+ADVANCED EXAMPLE
235
+
236
+The following code is an example of something fancier that can be done than just making creating
237
+the default accessor methods.
238
+
239
+A common task in many EOs is to have methods that will return sorted arrays of the to-many
240
+relationships.  While it is generally pretty easy to create these methods, it can become tedious
241
+if you have many relationships that need ordering.  This example provides a way to make generating
242
+those methods easier.
243
+
244
+It works by using the userInfo dictionary on an EORelationship.  You can put key-value pairs in
245
+that dictionary that can then be accessed by eogenerator to conditionally compile information.
246
+In the example below, the code looks to see if there is a key named 'sortMethods' defined in
247
+the userInfo dictionary.  If there is, then it presumes that the value will be an array of 
248
+dictionaries that define the sort methods. Each dictionary corresponds to one sort method,
249
+so that you can create multiple methods on a single relationship. This dictionary has one
250
+optional element, a key named 'by' and one required element, a key named 'ordering'. The 'by'
251
+key allows you to specify a extension to be tacked onto the method name. Because you can
252
+create multiple methods for sorting, this is needed to insure you don't have a name conflict.
253
+Note: The code doesn't check for conflicts, it just allows a way out.  The 'ordering' key takes
254
+an array of dictionaries itself.  These dictionaries just has one required element, a 'key' element
255
+and an optional 'sel' element.  The 'key' element should have the name of an attribute to sort
256
+on, while the 'sel' element is just the name of a EOSortOrdering selector, just the part after
257
+the 'EOSortOrdering.Compare' portion for simplicity. If no 'sel' value is given, then the code
258
+just uses Ascending.
259
+
260
+So say we have this example userInfo entry for 'sortMethods' on an 'employees' reletionship:
261
+
262
+  ({ by = NameAndDOB; ordering = ({key = name; sel = Ascending}, {key = dob; sel = Descending}); },
263
+   { ordering = ({key = name}) };)
264
+
265
+We end up with two methods:
266
+
267
+   public NSArray orderedEmployeesByNameAndDOB() // Ordered by ascending name and descending dob
268
+   public NSArray orderedEmployees()		 // Ordered by ascending name
269
+
270
+<$foreach SortMethod ToManyRelationship.userInfo.sortMethods sortmethodloop$><$
271
+  if SortMethod.ordering.@count gt 0$><$
272
+    if SortMethod.by ne ''$><$setmerge SortMethodBy = "By<$SortMethod.by$>"$><$endif$>
273
+
274
+    // Store the sort ordering in a private variable so that it won't take so long to execute the method
275
+    // especially useful if the sort method gets called a lot.
276
+    private static NSArray _orderingsFor<$ToManyRelationship.name.initialCapitalString$><$SortMethodBy$>;
277
+    
278
+    public NSArray ordered<$ToManyRelationship.name.initialCapitalString$><$SortMethodBy$>() {
279
+        NSArray objects = <$ToManyRelationship.name$>();
280
+        if ( objects.count() > 1 ) {
281
+            if ( _orderingsFor<$ToManyRelationship.name.initialCapitalString$><$SortMethodBy$> == null )
282
+                _orderingsFor<$ToManyRelationship.name.initialCapitalString$><$SortMethodBy$> = new NSArray(
283
+		    new Object[] {<$foreach Ordering SortMethod.ordering orderLoop$><$if OrderingIndex gt 0$>,<$endif$>
284
+                    	EOSortOrdering.sortOrderingWithKey("<$Ordering.key$>", EOSortOrdering.Compare<$if Ordering.sel$><$Ordering.sel$><$else$>Ascending<$endif$>)<$endforeach orderLoop$>
285
+                    }
286
+		);
287
+
288
+            objects = EOSortOrdering.sortedArrayUsingKeyOrderArray(objects, _orderingsFor<$ToManyRelationship.name.initialCapitalString$><$SortMethodBy$>);
289
+        }
290
+        return objects;
291
+    }<$
292
+  endif$><$
293
+endforeach sortmethodloop$>
294
+
295
+This may seem kind of complex and more effort than its worth, but a great many repetitive
296
+coding tasks can be accomplished by eogenerator in this same way.  You could have userInfo
297
+entries for attributes to do case conversion, do data conversion from one type to another
298
+(like T/F to boolean true/false), or create abbreviated strings of very long text. You could
299
+have to-many entries to setup filtering for some defined value(s) you provide.  You could
300
+even stick something in EOEntity's userInfo itself to setup some complex validation checking.
301
+
302
+We encourage you to explore the possibilities and if you find you've created some addition that is
303
+really useful, generic enough to be used by others, and you'd like to see included as an
304
+example here, your more than welcome to donate your ideas.
305
+
306
+$>
307
+<$endforeach tomanyrels$>
308
+}
309
+
0 310
new file mode 100644
... ...
@@ -0,0 +1,58 @@
0
+<$comment
1
+EOGenerator template for generated classes' Objective-C headers.
2
+This file is a more likely example of one to be actually used
3
+in a production environment, as it is much lighter-weight at
4
+#importing headers, and it shows how to do a custom EO superclass.
5
+
6
+BE SURE NOT TO INCLUDE DATES IN THIS FILE.  Since the "eogenerator"
7
+tool tries to compare the newly generated file with the old file,
8
+adding dates to this file will guarantee the old file gets
9
+overridden by the new file, forcing a recompilation of your EO.$>
10
+
11
+// <$GEN_PREFIX$><$className$>.h
12
+// 
13
+// Created by "eogenerator"
14
+// DO NOT EDIT.  Make changes to <$className$>.h instead.
15
+
16
+<$comment The below 'set' puts the FetchSpec into the global lookup space. We
17
+do this because the beautifiedFetchSpecificationDictionaries actually will
18
+print some logs and does a lot of object creation so this will keep the
19
+fuss down to a minimum.
20
+$><$set FetchSpecs = beautifiedFetchSpecificationDictionaries.@sortedNameArray$>
21
+
22
+<$if hasParentEntity$>
23
+#import <$parentObjCImportString$>
24
+<$else$>
25
+//#import <MyFramework/MyEOSuperclass.h>
26
+#import <EOControl/EOGenericRecord.h>
27
+<$endif$>
28
+<$foreach relationship referencedClasses.@reversedArray do$>
29
+@class <$relationship$>;<$endforeach do$>
30
+@class NSArray, NSMutableArray;
31
+
32
+@interface <$GEN_PREFIX$><$className$> : <$if hasParentEntity$><$parentClassName$><$else$>EOGenericRecord<$endif$>
33
+{
34
+}
35
+<$foreach attribute classAttributes.@sortedNameArray do$>
36
+- (void)set<$attribute.name.initialCapitalString$>:(<$attribute.valueClassName$> *)aValue;
37
+- (<$attribute.valueClassName$> *)<$attribute.name$>;
38
+<$endforeach do
39
+
40
+$><$foreach toOneRelationship classToOneRelationships.@sortedNameArray do$>
41
+- (void)set<$toOneRelationship.name.initialCapitalString$>:(<$toOneRelationship.destinationEntity.referenceClassName$>)aValue;
42
+- (<$toOneRelationship.destinationEntity.referenceClassName$>)<$toOneRelationship.name$>;
43
+- (void)set<$toOneRelationship.name.initialCapitalString$>Relationship:(<$toOneRelationship.destinationEntity.referenceClassName$>)aValue;
44
+<$endforeach do
45
+
46
+$><$foreach toManyRelationship classToManyRelationships.@sortedNameArray do$>
47
+- (void)set<$toManyRelationship.name.initialCapitalString$>:(NSMutableArray *)aValue;
48
+- (NSArray *)<$toManyRelationship.name$>;
49
+- (void)addTo<$toManyRelationship.name.initialCapitalString$>:(<$toManyRelationship.destinationEntity.referenceClassName$>)object;
50
+- (void)removeFrom<$toManyRelationship.name.initialCapitalString$>:(<$toManyRelationship.destinationEntity.referenceClassName$>)object;
51
+- (void)addTo<$toManyRelationship.name.initialCapitalString$>Relationship:(<$toManyRelationship.destinationEntity.referenceClassName$>)object;
52
+- (void)removeFrom<$toManyRelationship.name.initialCapitalString$>Relationship:(<$toManyRelationship.destinationEntity.referenceClassName$>)object;
53
+<$endforeach do
54
+
55
+$><$foreach FetchSpec FetchSpecs do$>
56
++ (NSArray *)objectsFor<$FetchSpec.niceName$>:(EOEditingContext *)context<$foreach Binding FetchSpec.bindings do2$> <$Binding.name$>:(<$Binding.codeType$>)<$Binding.name$>Binding<$endforeach do2$>;<$endforeach do$>
57
+@end
0 58
new file mode 100644
... ...
@@ -0,0 +1,121 @@
0
+<$comment
1
+EOGenerator template for generated classes' Objective-C source files.
2
+This file is a more likely example of one to be actually used
3
+in a production environment.
4
+
5
+BE SURE NOT TO INCLUDE DATES IN THIS FILE.  Since the "eogenerator"
6
+tool tries to compare the newly generated file with the old file,
7
+adding dates to this file will guarantee the old file gets
8
+overridden by the new file, forcing a recompilation of your EO.$>
9
+
10
+// <$GEN_PREFIX$><$className$>.m
11
+// 
12
+// Created by eogenerator
13
+// DO NOT EDIT.  Make changes to <$className$>.m instead.
14
+
15
+#import "<$GEN_PREFIX$><$className$>.h"
16
+#import <Foundation/Foundation.h>
17
+#import <EOControl/EOEditingContext.h>
18
+#import <EOControl/EOClassDescription.h>
19
+<$if FetchSpecs.@count > 0 $>
20
+#import <EOControl/EOFetchSpecification.h>
21
+<$endif$>
22
+<$comment  Use referencedObjCImportStrings instead of referencedClasses
23
+           for better #import handling for cross-framework relationships.
24
+$><$foreach importString referencedObjCImportStrings do$>#import <$importString$>
25
+<$endforeach do$>
26
+
27
+@implementation <$GEN_PREFIX$><$className$>
28
+
29
+// EOF invokes this init method when creating objects.
30
+- (id)initWithEditingContext:(EOEditingContext *)editingContext classDescription:(EOClassDescription *)classDesc globalID:(EOGlobalID *)gid
31
+{
32
+    self = [super initWithEditingContext:editingContext classDescription:classDesc globalID:gid];
33
+    return self;
34
+}
35
+
36
+// This init method is usually used from user code.
37
+- (id)init
38
+{
39
+    self = [super init];
40
+    return self;
41
+}
42
+
43
+<$foreach attribute classAttributes.@sortedNameArray do$>
44
+- (void)set<$attribute.name.initialCapitalString$>:(<$attribute.valueClassName$> *)aValue
45
+{
46
+    [self takeStoredValue:aValue forKey:@"<$attribute.name$>"];
47
+}
48
+- (<$attribute.valueClassName$> *)<$attribute.name$>
49
+{
50
+    return [self storedValueForKey:@"<$attribute.name$>"];
51
+}
52
+<$endforeach do$>
53
+
54
+<$foreach toOneRelationship classToOneRelationships.@sortedNameArray do$>
55
+- (void)set<$toOneRelationship.name.initialCapitalString$>:(<$toOneRelationship.destinationEntity.referenceClassName$>)aValue
56
+{
57
+    [self takeStoredValue:aValue forKey:@"<$toOneRelationship.name$>"];
58
+}
59
+- (<$toOneRelationship.destinationEntity.referenceClassName$>)<$toOneRelationship.name$>
60
+{
61
+    return [self storedValueForKey:@"<$toOneRelationship.name$>"];
62
+}
63
+- (void)set<$toOneRelationship.name.initialCapitalString$>Relationship:(<$toOneRelationship.destinationEntity.referenceClassName$>)aValue
64
+{
65
+    if (aValue == nil) {
66
+        <$toOneRelationship.destinationEntity.referenceClassName$>object = [self <$toOneRelationship.name$>];
67
+        if (object != nil)
68
+            [self removeObject:object fromBothSidesOfRelationshipWithKey:@"<$toOneRelationship.name$>"];
69
+    }
70
+    else {
71
+        [self addObject:aValue toBothSidesOfRelationshipWithKey:@"<$toOneRelationship.name$>"];
72
+    }
73
+}
74
+<$endforeach do$>
75
+
76
+<$foreach toManyRelationship classToManyRelationships.@sortedNameArray do$>
77
+- (void)set<$toManyRelationship.name.initialCapitalString$>:(NSMutableArray *)aValue
78
+{
79
+    [self takeStoredValue:aValue forKey:@"<$toManyRelationship.name$>"];
80
+}
81
+- (NSArray *)<$toManyRelationship.name$>
82
+{
83
+    return [self storedValueForKey:@"<$toManyRelationship.name$>"];
84
+}
85
+- (void)addTo<$toManyRelationship.name.initialCapitalString$>:(<$toManyRelationship.destinationEntity.referenceClassName$>)object
86
+{
87
+    NSMutableArray *array = (NSMutableArray *)[self <$toManyRelationship.name$>];
88
+    [self willChange];
89
+    [array addObject:object];
90
+}
91
+- (void)removeFrom<$toManyRelationship.name.initialCapitalString$>:(<$toManyRelationship.destinationEntity.referenceClassName$>)object
92
+{
93
+    NSMutableArray *array = (NSMutableArray *)[self <$toManyRelationship.name$>];
94
+    [self willChange];
95
+    [array removeObject:object];
96
+}
97
+- (void)addTo<$toManyRelationship.name.initialCapitalString$>Relationship:(<$toManyRelationship.destinationEntity.referenceClassName$>)object
98
+{
99
+    [self addObject:object toBothSidesOfRelationshipWithKey:@"<$toManyRelationship.name$>"];
100
+}
101
+- (void)removeFrom<$toManyRelationship.name.initialCapitalString$>Relationship:(<$toManyRelationship.destinationEntity.referenceClassName$>)object
102
+{
103
+    [self removeObject:object fromBothSidesOfRelationshipWithKey:@"<$toManyRelationship.name$>"];
104
+}
105
+<$endforeach do$>
106
+
107
+<$foreach FetchSpec FetchSpecs do$>
108
++ (NSArray *)objectsFor<$FetchSpec.niceName$>:(EOEditingContext *)context<$foreach Binding FetchSpec.bindings do2$> <$Binding.name$>:(<$Binding.codeType$>)<$Binding.name$>Binding<$endforeach do2$>
109
+{
110
+    EOFetchSpecification *spec = [EOFetchSpecification fetchSpecificationNamed:@"<$FetchSpec.fetchName$>" entityNamed:@"<$name$>"];<$if FetchSpec.bindings.@count gt 0$>
111
+    NSMutableDictionary *bindings = [NSMutableDictionary dictionary];
112
+<$foreach Binding FetchSpec.bindings do2$>
113
+    if ( <$Binding.name$>Binding != nil )
114
+        [bindings setObject:<$Binding.name$>Binding forKey:@"<$Binding.name$>"];<$endforeach do2$>
115
+    spec = [spec fetchSpecificationWithQualifierBindings:bindings];
116
+<$endif$>
117
+    return [context objectsWithFetchSpecification:spec];
118
+}
119
+<$endforeach do$>
120
+@end
0 121
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+#import <EOAccess/EOModel.h>
1
+#import <EOAccess/EOModelGroup.h>
2
+#import <EOAccess/EOEntity.h>
3
+#import <EOAccess/EOAttribute.h>
4
+#import <EOAccess/EORelationship.h>
0 5
new file mode 100644
... ...
@@ -0,0 +1,8 @@
0
+#import <Foundation/NSObject.h>
1
+@interface EOAttribute : NSObject
2
+{
3
+    id padding[30];
4
+}
5
+-(id)valueType;
6
+-(id)valueClassName;
7
+@end
0 8
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+#import <Foundation/NSString.h>
1
+
2
+@interface EOEntity
3
+-(id)name;
4
+-(id)parentEntity;
5
+-(NSString *)frameworkName;
6
+-(id)model;
7
+-(id)className;
8
+-(id)relationships;
9
+-(id)className;
10
+-(id)attributeNamed:(id)name;
11
+-(id)relationshipNamed:(id)name;
12
+-(id)fetchSpecificationNames;
13
+-(id)fetchSpecificationNamed:(id)name;
14
+@end
15
+
16
+@interface NSString (EOEntityAdditions)
17
++ (NSString *)externalNameForInternalName:(NSString *)name separatorString:(NSString *)separatorString useAllCaps:(BOOL)useAllCaps;
18
++ (NSString *)nameForExternalName:(NSString *)name separatorString:(NSString *)separatorString initialCaps:(BOOL)initialCaps;
19
+@end
0 20
new file mode 100644
... ...
@@ -0,0 +1,10 @@
0
+#import <Foundation/NSObjCRuntime.h>
1
+@interface EOModel
2
++ (id)alloc;
3
+-(id)userInfo;
4
+-(NSString *)path;
5
+-(id)entities;
6
+-(NSString *)name;
7
+-setUserInfo:(id)userInfo;
8
+-release;
9
+@end
0 10
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+@interface EOModelGroup
1
++(id)alloc;
2
++(id)defaultGroup;
3
++setDefaultGroup:(id)group;
4
+-setDelegate:(id)delegate;
5
+-(id)modelNamed:(id)name;
6
+-addModel:(id)model;
7
+-(id)entityNamed:(id)name;
8
+@end
0 9
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+@interface EORelationship
1
+-(id)destinationEntity;
2
+-(id)entity;
3
+-(id)name;
4
+@end
0 5
new file mode 100644
... ...
@@ -0,0 +1,5 @@
0
+@interface EOClassDescription
1
++(id)classDescriptionForEntityName:(id)name;
2
+-(id)classDescriptionForDestinationKey:(id)key;
3
+-(BOOL)isKindOfClass:(id)class;
4
+@end
0 5
new file mode 100644
... ...
@@ -0,0 +1,4 @@
0
+@interface EOEntityClassDescription
1
++(id)class;
2
+-(id)entity;
3
+@end
0 4
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+#import <EOControl/EOClassDescription.h>
1
+#import <EOControl/EOEntityClassDescription.h>
2
+
3
+@interface EOFetchSpecification
4
+-(id)entityName;
5
+-(id)qualifier;
6
+-(id)bindingKeys;
7
+-(id)keyPathForBindingKey:(id)bindingKey;
8
+@end
0 9
new file mode 100644