0)
{
EOAdaptor *adaptor;
adaptor = [EOAdaptor adaptorWithName: _adaptorName];
attributes = [adaptor prototypeAttributes];
}
else
attributes = [entity attributes];
EOFLOGObjectLevelArgs(@"gsdb", @"entity=%@ - attributes=%@",
entity, attributes);
if (attributes)
{
count = [attributes count];
for (i = 0; i < count; i++)
{
attribute = [attributes objectAtIndex: i];
if ([[attribute name]
isEqualToString: attributeName])
break;
}
}
EOFLOGObjectLevelArgs(@"gsdb", @"attribute=%@", attribute);
return attribute;
}
@end
@implementation EOModel (EOModelFileAccess)
+ (EOModel*) modelWithContentsOfFile: (NSString *)path
{
return AUTORELEASE([[self alloc] initWithContentsOfFile: path]);
}
- (id) initWithContentsOfFile: (NSString *)path
{
NS_DURING
{
NSString *name = nil;
NSString *modelPath = nil;
NSString *indexPath = nil;
NSString *fileContents = nil;
NSDictionary *propList = nil;
path = [path stringByStandardizingPath];
modelPath = [isa _formatModelPath: path checkFileSystem: YES];
NSAssert1(modelPath!=nil, @"Model does not exist at path %@",
path );
name = [[modelPath lastPathComponent] stringByDeletingPathExtension];
[self setName: name];
if ([[modelPath pathExtension] isEqualToString: @"eomodeld"])
{
indexPath =
[modelPath stringByAppendingPathComponent: @"index.eomodeld"];
}
else
{
indexPath = modelPath;
}
fileContents = [NSString stringWithContentsOfFile: indexPath];
NSAssert1(fileContents!=nil, @"File %@ could not be read.", indexPath);
propList = [fileContents propertyList];
EOFLOGObjectLevelArgs(@"gsdb", @"propList=%@", propList);
NSAssert1(propList!=nil, @"Model at path %@ is invalid", indexPath);
self = [self initWithTableOfContentsPropertyList: propList
path: modelPath];
NSAssert2(self!=nil,@"Failed to initialize with path %@ and plist %@",
modelPath,
propList);
}
NS_HANDLER
{
NSLog(@"exception in EOModel initWithContentsOfFile:");
NSLog(@"exception=%@", localException);
[localException raise];
}
NS_ENDHANDLER;
return self;
}
- (BOOL) _writePlist:(NSDictionary*)plist toFile:(NSString*) path
{
NSData * fileData;
NSString * errorDescription = nil;
NSError * error = nil;
BOOL ok = NO;
// we should use
// NSPropertyListSerialization dataWithPropertyList:format:options:error:
// but that is not hacked to work on apple in Additions
fileData = [NSPropertyListSerialization dataFromPropertyList:plist
format:NSPropertyListOpenStepFormat
errorDescription:&errorDescription];
if (!fileData) {
NSLog(@"%s: Cannot convert plist to data.", __PRETTY_FUNCTION__);
return NO;
}
ok = [fileData writeToFile:path
options:NSAtomicWrite
error:&error];
if (!ok) {
NSLog(@"%s:%@", __PRETTY_FUNCTION__, error);
}
return ok;
}
/**
* Deletes any non-known files/paths at path.
* private.
*/
- (void) _deleteTrashAtPath:(NSString*) path
{
NSFileManager * manager = [NSFileManager defaultManager];
NSDirectoryEnumerator * dirEnumer = [manager enumeratorAtPath:path];
NSArray * knownTrashPaths = [NSArray arrayWithObjects:@".svn",
@".CVS", @".git",
nil];
NSString * fileName = nil;
while ((fileName = [dirEnumer nextObject])) {
NSString * prefix = [[fileName pathComponents] objectAtIndex:0];
if (([knownTrashPaths containsObject:prefix] == NO)) {
NSString * fullPath = nil;
fullPath = [path stringByAppendingPathComponent:fileName];
if ([manager removeFileAtPath: fullPath handler: nil] == NO)
{
[NSException raise: NSInvalidArgumentException
format: @"Could not remove %@", fullPath];
}
}
}
}
/**
* Writes the receivers plist representation into an
* .eomodeld file wrapper located at path.
* Depending on the the path extension .eomodeld or .eomodel
* the corresponding format will be used.
* If the path has neither .eomodeld nor .eomodel path
* extension, .eomodeld will be used.
* If the file located at path already exists, a back is created
* by appending a '~' character to file name.
* If a backup file already exists, when trying to create a backup,
* the old backup will be deleted.
* If any of the file operations fail, an NSInvalidArgumentException
* will be raised.
* This method as the side effeect of setting the receivers path and
* name. The this change can happen even if the write operation fails
* with an exception.
*/
- (void)writeToFile: (NSString *)path
{
NSFileManager *mgr = [NSFileManager defaultManager];
NSMutableDictionary *pList;
NSDictionary *entityPList;
NSDictionary *stProcPList;
NSEnumerator *entityEnum;
NSEnumerator *stProcEnum;
NSString *fileName;
NSString *extension;
BOOL writeSingleFile;
[self loadAllModelObjects];
path = [path stringByStandardizingPath];
extension = [path pathExtension];
if ([extension isEqualToString: @"eomodeld"] == NO
&& [extension isEqualToString: @"eomodel"] == NO)
{
path = [path stringByAppendingPathExtension: @"eomodeld"];
extension = [path pathExtension];
}
writeSingleFile = [extension isEqualToString: @"eomodel"] ? YES : NO;
/*
* Don't copy directories. EOModelEditor and NSDocument do all the magic for us.
*/
/*
if ([mgr fileExistsAtPath: path])
{
NSString *backupPath;
backupPath = [path stringByAppendingString: @"~"];
if ([mgr fileExistsAtPath: backupPath])
{
if ([mgr removeFileAtPath: backupPath handler: nil] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not remove %@",
backupPath];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
if ([mgr movePath: path toPath: backupPath handler: nil] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not move %@ to %@",
path, backupPath];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
*/
[self _setPath: path];
pList = [NSMutableDictionary dictionaryWithCapacity: 10];
[self encodeIntoPropertyList: pList];
// create an dir only if we have none.
if (![mgr fileExistsAtPath: path])
{
if (writeSingleFile == NO
&& [mgr createDirectoryAtPath: path attributes: nil] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not create directory: %@",
path];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
[self _deleteTrashAtPath:path];
entityEnum = [[pList objectForKey: @"entities"] objectEnumerator];
while (writeSingleFile == NO
&& (entityPList = [entityEnum nextObject]))
{
NSString *fileName;
fileName = [path stringByAppendingPathComponent:
[NSString stringWithFormat: @"%@.plist",
[entityPList objectForKey: @"name"]]];
if ([self _writePlist:entityPList toFile:fileName] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not create file: %@",
fileName];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
stProcEnum = [[pList objectForKey: @"storedProcedures"] objectEnumerator];
while (writeSingleFile == NO
&& (stProcPList = [stProcEnum nextObject]))
{
NSString *fileName;
fileName = [stProcPList objectForKey: @"name"];
fileName = [fileName stringByAppendingPathExtension: @"storedProcedure"];
fileName = [path stringByAppendingPathComponent: fileName];
if ([self _writePlist:stProcPList toFile:fileName] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not create file: %@",
fileName];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
if (writeSingleFile == NO)
{
fileName = [path stringByAppendingPathComponent: @"index.eomodeld"];
[pList removeAllObjects];
[self encodeTableOfContentsIntoPropertyList: pList];
}
else
{
fileName = path;
}
if ([self _writePlist:pList toFile:fileName] == NO)
{
NSString *fmt;
fmt = [NSString stringWithFormat: @"Could not create file: %@",
fileName];
[NSException raise: NSInvalidArgumentException
format: fmt];
}
}
@end
@implementation EOModel (EOModelPropertyList)
- (id)initWithTableOfContentsPropertyList: (NSDictionary *)tableOfContents
path: (NSString *)path
{
//OK
NS_DURING
{
if ((self = [self init]))
{
NSString *modelPath;
NSString *versionString = nil;
NSArray *entities = nil;
int i, count = 0;
EOFLOGObjectLevelArgs(@"gsdb", @"tableOfContents=%@",
tableOfContents);
/* The call to _setPath: also sets the name implicitly. */
modelPath = [isa _formatModelPath: path checkFileSystem: YES];
[self _setPath: modelPath];
EOFLOGObjectLevelArgs(@"gsdb", @"name=%@ path=%@", _name, _path);
versionString = [tableOfContents objectForKey: @"EOModelVersion"];
if (versionString)
_version = [versionString floatValue];
else
_version = 0; // dayers: is this correct?
ASSIGN(_connectionDictionary,
[tableOfContents objectForKey: @"connectionDictionary"]);
ASSIGN(_adaptorName, [tableOfContents objectForKey: @"adaptorName"]);
ASSIGN(_userInfo, [tableOfContents objectForKey: @"userInfo"]);
if (!_userInfo)
{
ASSIGN(_userInfo,
[tableOfContents objectForKey:@"userDictionary"]);
}
ASSIGN(_internalInfo,
[tableOfContents objectForKey: @"internalInfo"]);
ASSIGN(_docComment,[tableOfContents objectForKey:@"docComment"]);
//VERIFY
if (_version >= 2)
{
NSMutableDictionary *markSP = [NSMutableDictionary dictionary];
NSArray *storedProcedures
= [tableOfContents objectForKey: @"storedProcedures"];
count = [storedProcedures count];
for (i = 0; i < count; i++)
{
EOStoredProcedure *proc;
NSDictionary *plist;
NSString *fileName;
NSString *procName;
NSString *fullPath;
procName = [storedProcedures objectAtIndex: i];
fileName = [procName stringByAppendingPathExtension:
@"storedProcedure"];
fullPath = [_path stringByAppendingPathComponent: fileName];
plist
= [NSDictionary dictionaryWithContentsOfFile: fullPath];
NSAssert2([procName isEqual: [plist objectForKey: @"name"]],
@"Name mismatch: index.plist: %@"
@" *.storedProcedure: %@", procName,
[plist objectForKey: @"name"]);
[markSP setObject: plist forKey: procName];
proc
= [EOStoredProcedure storedProcedureWithPropertyList: plist
owner: self];
[self addStoredProcedure: proc];
}
count = [_storedProcedures count];
for (i = 0; i < count; i++)
{
EOStoredProcedure *proc;
NSString *name;
NSDictionary *plist;
proc = [_storedProcedures objectAtIndex: i];
name = [proc name];
plist = [markSP objectForKey: name];
if (plist)
{
[proc awakeWithPropertyList: plist];
}
}
}
entities = [tableOfContents objectForKey: @"entities"];
count = [entities count];
for (i=0; i= 2)
{
NSString *fileName = [NSString stringWithFormat: @"%@.plist",
[plist objectForKey: @"name"]];
plist = [[NSString stringWithContentsOfFile:
[_name stringByAppendingPathComponent:
fileName]]
propertyList];
}
[markEntities setObject: plist
forKey: [plist objectForKey: @"name"]];
entity
= AUTORELEASE([[EOEntity alloc] initWithPropertyList: plist
owner: self]);
[self addEntity: entity];
}
/* Do not access _entities until cache is triggered */
enumerator = [[self entities] objectEnumerator];
while ((entity = [enumerator nextObject]))
{
NS_DURING
{
[entity awakeWithPropertyList:
[markEntities objectForKey: [entity name]]];
}
NS_HANDLER
{
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: exception in model '%@' during awakeWithPropertyList: of entity '%@': %@",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
[self name],
[entity name],
[localException reason]];
}
NS_ENDHANDLER;
}
if (_version >= 2)
{
count = [propListSt count];
for (i = 0; i < count; i++)
{
EOStoredProcedure *st;
NSDictionary *plist;
NSString *fileName;
fileName = [NSString stringWithFormat: @"%@.storedProcedure",
[[propListSt objectAtIndex: i]
objectForKey: @"name"]];
plist = [[NSString stringWithContentsOfFile:
[_name stringByAppendingPathComponent:
fileName]]
propertyList];
[markSP setObject: plist
forKey: [plist objectForKey: @"name"]];
st = [EOStoredProcedure storedProcedureWithPropertyList: plist
owner: self];
[self addStoredProcedure: st];
}
enumerator = [_storedProcedures objectEnumerator];
while ((sp = [enumerator nextObject]))
[sp awakeWithPropertyList: [markSP objectForKey: [sp name]]];
}
}
}
NS_HANDLER
{
NSLog(@"exception in EOModel initWithPropertyList:owner:");
NSLog(@"exception=%@", localException);
[localException raise];
}
NS_ENDHANDLER;
return self;
}
- (void)awakeWithPropertyList: (NSDictionary *)propertyList
{
return;
}
- (void)encodeIntoPropertyList: (NSMutableDictionary *)propertyList
{
int i, count;
[propertyList setObject:
[[NSNumber numberWithFloat: DEFAULT_MODEL_VERSION]
stringValue]
forKey: @"EOModelVersion"];
if (_name)
[propertyList setObject: _name forKey: @"name"];
if (_adaptorName)
[propertyList setObject: _adaptorName forKey: @"adaptorName"];
if (_adaptorClassName)
[propertyList setObject: _adaptorClassName forKey: @"adaptorClassName"];
if (_connectionDictionary)
[propertyList setObject: _connectionDictionary
forKey: @"connectionDictionary"];
if (_userInfo)
[propertyList setObject: _userInfo forKey: @"userInfo"];
if (_internalInfo)
[propertyList setObject: _internalInfo forKey: @"internalInfo"];
if (_docComment)
[propertyList setObject: _docComment forKey: @"docComment"];
/* Do not access _entities until cache is triggered */
count = [[self entities] count];
if (count > 0)
{
NSMutableArray *entitiesArray = [NSMutableArray arrayWithCapacity: count];
[propertyList setObject: entitiesArray forKey: @"entities"];
for (i = 0; i < count; i++)
{
NSMutableDictionary *entityPList = [NSMutableDictionary dictionary];
EOEntity *entity = [_entities objectAtIndex: i];
[entity encodeIntoPropertyList: entityPList];
[entitiesArray addObject: entityPList];
}
}
count = [_storedProcedures count];
if (count > 0)
{
NSMutableArray *stArray = [NSMutableArray arrayWithCapacity: count];
[propertyList setObject: stArray forKey: @"storedProcedures"];
for (i = 0; i < count; i++)
{
NSMutableDictionary *stPList = [NSMutableDictionary dictionary];
EOStoredProcedure *proc = [_storedProcedures objectAtIndex: i];
[proc encodeIntoPropertyList: stPList];
[stArray addObject: stPList];
}
}
}
@end
@implementation EOModel (EOModelHidden)
- (NSMutableDictionary *) _loadFetchSpecificationDictionaryForEntityNamed:(NSString *) entName
{
NSEmitTODO();
return nil;
}
-(void) _classDescriptionNeeded: (NSNotification *)notification
{
//TODO
NSString *notificationName = nil;
notificationName = [notification name];
EOFLOGObjectLevelArgs(@"gsdb", @"notificationName=%@", notificationName);
if ([notificationName
isEqualToString: EOClassDescriptionNeededForClassNotification])
{
Class aClass = [notification object];
EOClassDescription *classDescription = nil;
EOEntity *entity = nil;
NSString *entityClassName = nil;
EOFLOGObjectLevelArgs(@"gsdb", @"notification=%@ aClass=%@",
notification, aClass);
NSAssert(aClass, @"No class");
entity = [self _entityForClass: aClass];
if (!entity)
{
NSAssert1((!GSObjCIsKindOf(aClass, [EOGenericRecord class])),
@"No entity for class %@", aClass);
}
else
{
Class entityClass=Nil;
classDescription = [entity classDescriptionForInstances];
EOFLOGObjectLevelArgs(@"gsdb", @"classDescription=%@",
classDescription);
entityClassName = [entity className];
EOFLOGObjectLevelArgs(@"gsdb",@"entityClassName=%@",entityClassName);
entityClass=NSClassFromString(entityClassName);
NSAssert1(entityClass,@"No entity class named '%@'",entityClassName);
[EOClassDescription registerClassDescription: classDescription
forClass: entityClass];
}
}
else if ([notificationName
isEqualToString: EOClassDescriptionNeededForEntityNameNotification])
{
//OK
EOClassDescription *classDescription;
NSString *entityName = [notification object];
EOEntity *entity = nil;
NSString *entityClassName = nil;
Class entityClass = Nil;
EOFLOGObjectLevelArgs(@"gsdb", @"notification=%@", notification);
EOFLOGObjectLevelArgs(@"gsdb", @"entityName=%@", entityName);
NSAssert(entityName, @"No entity name");//??
entity = [self entityNamed: entityName];
NSAssert1(entity, @"No entity named %@", entityName);//??
classDescription = [entity classDescriptionForInstances];
EOFLOGObjectLevelArgs(@"gsdb", @"classDescription=%@", classDescription);
entityClassName = [entity className];
EOFLOGObjectLevelArgs(@"gsdb", @"entityClassName=%@", entityClassName);
entityClass=NSClassFromString(entityClassName);
NSAssert1(entityClass,@"No entity class named '%@'",entityClassName);
[EOClassDescription registerClassDescription: classDescription
forClass:entityClass];//??
}
else if ([notificationName
isEqualToString: EOClassDescriptionNeededNotification])
{
//TODO
}
else
{
//TODO
}
}
- (void) _resetPrototypeCache
{
// TODO
[self notImplemented: _cmd];
}
- (BOOL) isPrototypesEntity: (id)param0
{
// TODO
[self notImplemented: _cmd];
return NO;
}
- (id) _instantiatedEntities
{
// TODO
[self notImplemented: _cmd];
return nil;
}
- (void) _setPath: (NSString*)path
{
//OK
[self loadAllModelObjects];
[self willChange];
ASSIGN(_path, path);
[self setName: [[path lastPathComponent] stringByDeletingPathExtension]];
}
- (EOEntity*) _entityForClass: (Class)aClass
{
NSString *className;
EOEntity *entity;
NSAssert(aClass, @"No class");
NSAssert(_entitiesByClass, @"No _entitiesByClass");
className = NSStringFromClass(aClass);
EOFLOGObjectLevelArgs(@"gsdb", @"className=%@", className);
entity = NSMapGet(_entitiesByClass, className);
EOFLOGObjectLevelArgs(@"gsdb", @"entity class=%@", [entity class]);
if (entity)
{
entity = [self _verifyBuiltEntityObject: entity
named: nil];
EOFLOGObjectLevelArgs(@"gsdb", @"entity=%@", entity);
}
else
{
EOFLOGObjectLevelArgs(@"gsdb", @"entity for class named=%@ not found",
className);
EOFLOGObjectLevelArgs(@"gsdb", @"entities class names=%@",
NSAllMapTableKeys(_entitiesByClass));
EOFLOGObjectLevelArgs(@"gsdb", @"entities entities names=%@",
NSAllMapTableValues(_entitiesByClass));
EOFLOGObjectLevelArgs(@"gsdb", @"entities map=%@",
NSStringFromMapTable(_entitiesByClass));
}
return entity;
}
- (id) _childrenForEntityNamed: (id)param0
{
// TODO [self notImplemented:_cmd];
return nil;
}
- (void) _registerChild: (id)param0
forParent: (id)param1
{
// TODO [self notImplemented:_cmd];
return;
}
- (void) _setInheritanceLinks: (id)param0
{
// TODO
[self notImplemented: _cmd];
return;
}
/**
* Before removing attributes we need to remove all references
*/
- (void) _removePropertiesReferencingProperty:(id) property
{
NSUInteger refCount, refIdx = 0;
NSArray * references = nil;
references = [self referencesToProperty:property];
refCount = [references count];
for (; refIdx < refCount; refIdx++) {
id refObj = [references objectAtIndex:refIdx];
if ([refObj class] == [EOAttribute class])
{
[[(EOAttribute*) refObj entity] removeAttribute:refObj];
} else {
[[(EORelationship*) refObj entity] removeRelationship:refObj];
}
}
}
/**
* Before removing entities we need to remove all references
*/
- (void) _removePropertiesReferencingEntity:(EOEntity*) entity
{
int i;
for (i = 0; i < 2; i++)
{
NSArray * attrsOrRels;
NSArray * names = nil;
NSUInteger index = 0;
NSUInteger count = 0;
if ((i == 0))
{
attrsOrRels = [entity attributes];
} else {
attrsOrRels = [entity relationships];
}
// get name from the array
names = [attrsOrRels resultsOfPerformingSelector:@selector(name)];
for (count = [names count]; index < count; index++)
{
id attrOrRel = nil;
if (i == 0) {
attrOrRel = [entity attributeNamed:[names objectAtIndex:index]];
} else {
attrOrRel = [entity relationshipNamed:[names objectAtIndex:index]];
}
if (attrOrRel) {
[self _removePropertiesReferencingProperty:attrOrRel];
}
}
}
}
- (void) _removeEntity: (EOEntity *)entity
{
//should be ok
NSString *entityName = nil;
NSString *entityClassName = nil;
if ([entity isKindOfClass: [EOEntity class]])
{
entityName = [entity name];
entityClassName = [entity className];
}
else
{
entityName = [(NSDictionary *)entity objectForKey: @"name"];
entityClassName = [(NSDictionary *)entity objectForKey: @"className"];
}
[_entitiesByName removeObjectForKey: entityName];
if (_entitiesByClass)
NSMapRemove(_entitiesByClass, entityClassName);
DESTROY(_entities);
}
- (EOEntity*) _addEntityWithPropertyList: (NSDictionary*)propertyList
{
//OK
id children = nil;
EOEntity *entity = nil;
NSAssert(propertyList, @"no propertyList");
EOFLOGObjectLevelArgs(@"gsdb", @"propertyList=%@", propertyList);
entity = AUTORELEASE([[EOEntity alloc] initWithPropertyList: propertyList
owner: self]);
NSAssert2([entity className], @"Entity %p named %@ has no class name",
entity, [entity name]);
entity = [self _addEntity: entity];
children = [self _childrenForEntityNamed: [entity name]];
if (children)
{
[self notImplemented: _cmd];//TODO
//may be: self _registerChild:(id)param0
// forParent:entity...
}
[entity awakeWithPropertyList:propertyList];
[[NSNotificationCenter defaultCenter]
postNotificationName: @"EOEntityLoadedNotification"
object: entity];
return entity;
}
- (void) _addFakeEntityWithPropertyList: (NSDictionary*)propertyList
{
//OK
NSString *entityName;
NSString *className;
NSAssert(propertyList, @"no propertyList");
entityName = [propertyList objectForKey: @"name"];
className = [propertyList objectForKey: @"className"];
NSAssert1(entityName, @"No entity name in %@", propertyList);
NSAssert1(className, @"No class name in %@", propertyList);
[self _setEntity: propertyList
forEntityName: entityName
className: className];
DESTROY(_entities); //To force rebuild
}
- (id) _addEntity: (EOEntity*)entity
{
//Seems OK
NSString *entityClassName;
NSAssert(entity, @"No entity to add");
EOFLOGObjectLevelArgs(@"gsdb", @"model _addEntity=%@", [entity name]);
entityClassName = [entity className];
NSAssert2(entityClassName, @"Entity %p named %@ has no class name",
entity, [entity name]);
//May be returning a previous entity of that name if any ?
[self _setEntity: entity
forEntityName: [entity name]
className: entityClassName];
[entity _setModel: self];
return entity;
}
//entity can be a EOEntity or an entity PList
- (void) _setEntity: (id)entity
forEntityName: (NSString*)entityName
className: (NSString*)className
{
NSAssert(entityName, @"No entity name");
NSAssert(className, @"No class name");
NSAssert1([_entitiesByName objectForKey: entityName] == nil,
@"Entity '%@' is already registered with this model",
entityName);
//Seems OK
[_entitiesByName setObject: entity
forKey: entityName];
NSAssert(_entitiesByClass, @"No entities by class");
if (NSMapGet(_entitiesByClass, className))
NSMapRemove(_entitiesByClass, className);
NSMapInsertIfAbsent(_entitiesByClass, className, entity);
}
@end
@implementation EOModel (EOModelEditing)
- (void) setName: (NSString *)name
{
if (![name isEqualToString: _name])
{
EOModelGroup *group;
AUTORELEASE(RETAIN(self));
group = [self modelGroup];
if (group)
{
[group removeModel: self];
}
[self willChange];
ASSIGNCOPY(_name, name);
if (group)
{
[group addModel: self];
}
}
}
- (void) setAdaptorName: (NSString *)adaptorName
{
[self willChange];
ASSIGNCOPY(_adaptorName, adaptorName);
}
- (void) setConnectionDictionary: (NSDictionary *)connectionDictionary
{
[self willChange];
ASSIGN(_connectionDictionary, connectionDictionary);
}
- (void) setUserInfo: (NSDictionary *)userInfo
{
[self willChange];
ASSIGN(_userInfo, userInfo);
}
- (void) setDocComment: (NSString *)docComment
{
[self willChange];
ASSIGNCOPY(_docComment, docComment);
}
- (void) addEntity: (EOEntity *)entity
{
NSString *entityName = [entity name];
// void *entitiesClass;
// int count;
NSString *className = nil;
if (!entity)
{
[NSException raise: NSInvalidArgumentException
format: @"%s entity is nil.", __PRETTY_FUNCTION__];
}
if (([entity model] != nil) && ([entity model] != self))
{
[NSException raise: NSInvalidArgumentException
format: @"%s %@ already registered with model named '%@'",
__PRETTY_FUNCTION__,
entityName, [[entity model] name]];
}
if ([_entitiesByName objectForKey:[entity name]])
{
[NSException raise: NSInvalidArgumentException
format: @"%s Cannot register two entities with the same name",
__PRETTY_FUNCTION__];
}
[self willChange];
/* _entities is sorted. we want a new one! */
if (_entities) {
DESTROY(_entities);
}
NSAssert(_entitiesByClass, @"No _entitiesByClass");
className = [entity className];
NSAssert1(className, @"No className in %@", entity);
if (NSMapGet(_entitiesByClass, className))
NSMapRemove(_entitiesByClass, className);
NSMapInsertIfAbsent(_entitiesByClass, className, entity);
[_entitiesByName setObject: entity
forKey: entityName];
[entity _setModel: self];
}
/**
* Removes the entity without performing any referential integrity checking.
*/
- (void) removeEntity: (EOEntity *)entity
{
// TODO: find out why removeEntity: and _removeEntity: exists
[self _removeEntity:entity];
}
- (void) removeEntityAndReferences: (EOEntity *)entity
{
NSArray * subEntities;
NSEnumerator * subEnumer;
EOEntity * subEntity;
[self _removePropertiesReferencingEntity:entity];
subEntities = [NSArray arrayWithArray:[entity subEntities]];
subEnumer = [subEntities objectEnumerator];
while ((subEntity = [subEnumer nextObject])) {
[entity removeSubEntity:subEntity];
}
[self removeEntity: entity];
}
- (void)addStoredProcedure: (EOStoredProcedure *)storedProcedure
{
if ([self storedProcedureNamed: [storedProcedure name]])
[NSException raise: NSInvalidArgumentException
format: @"%@ -- %@ 0x%x: \"%@\" already registered as stored procedure name ",
NSStringFromSelector(_cmd),
NSStringFromClass([self class]),
self,
[storedProcedure name]];
NSAssert(_storedProcedures, @"Uninitialised _storedProcedures!");
[self willChange];
[(NSMutableArray *)_storedProcedures addObject: storedProcedure];
}
- (void)removeStoredProcedure: (EOStoredProcedure *)storedProcedure
{
NSAssert(_storedProcedures, @"Uninitialised _storedProcedures!");
[self willChange];
[(NSMutableArray *)_storedProcedures removeObject: storedProcedure];
}
- (void) setModelGroup: (EOModelGroup *)group
{
//call group _addSubEntitiesCache:
_group = group;
}
- (void)loadAllModelObjects
{
NSArray *entityNames = [_entitiesByName allKeys];
NSUInteger i,n = [entityNames count];
[self storedProcedures];
for (i=0; i 0) {
[refProps addObjectsFromArray:newArray];
}
}
}
propEnumerator = [[ent relationships] objectEnumerator];
propEnumNO = NULL;
while ((rel = GDL2_NextObjectWithImpPtr(propEnumerator, &propEnumNO)))
{
if ([rel referencesProperty:property])
{
NSArray * newArray;
[refProps addObject:rel];
newArray = [self referencesToProperty:rel];
if ([newArray count] > 0) {
[refProps addObjectsFromArray:newArray];
}
}
}
}
return [refProps count] ? [NSArray arrayWithArray:refProps] : nil;
}
- (NSArray *) externalModelsReferenced
{
// TODO;
[self notImplemented: _cmd];
return nil;
}
@end
@implementation EOModel (EOModelBeautifier)
- (void) beautifyNames
{
NSArray *listItems;
NSString *newString = [NSString string];
int anz, i, count;
EOFLOGObjectFnStartOrCond2(@"ModelingClasses", @"EOModel");
/* Makes the receiver's name conform to a standard convention.
Names that conform to this style are all lower-case except
for the initial letter of each embedded word other than the
first, which is upper case. Thus, "NAME" becomes "name", and
"FIRST_NAME" becomes "firstName". */
if ((_name) && ([_name length] > 0))
{
listItems = [_name componentsSeparatedByString: @"_"];
newString = [newString stringByAppendingString:
[(NSString *)[listItems objectAtIndex: 0]
lowercaseString]];
anz = [listItems count];
for (i = 1; i < anz; i++)
{
newString = [newString stringByAppendingString:
[(NSString *)[listItems objectAtIndex: i]
capitalizedString]];
}
// Exception abfangen
NS_DURING
{
// Model Name
[self setName: newString];
// Entites
/* Do not access _entities until cache is triggered */
if ([self entities] && (count = [_entities count]))
{
for (i = 0; i < count; i++)
[(EOEntity *)[_entities objectAtIndex:i] beautifyName];
}
}
NS_HANDLER
NSLog(@"%@ in Class: EOEntity , Method: beautifyName >> error : %@",
[localException name], [localException reason]);
NS_ENDHANDLER;
}
EOFLOGObjectFnStopOrCond2(@"ModelingClasses", @"EOModel");
}
@end
@implementation EOModel (EOModelPrivate)
/**
* Returns a string that can be uses as a model path to load or save
* the model. If chkFS is YES, then the path is searched. If path
* does not include a path extension then first .eomodeld checked. If that
* fails then .eomodel is searched. Call this method to format the path
* provided before saving the model with chkFS NO. Call this method to
* format the path provided before loading a model with chkFS YES.
*/
+ (NSString *) _formatModelPath: (NSString *)path checkFileSystem: (BOOL)chkFS
{
NSFileManager *fileManager;
NSString *lastPathComponent = nil;
NSString *pathExtension = nil;
NSString *searchPath = path;
NSString *returnPath = path;
lastPathComponent = [path lastPathComponent];
pathExtension = [lastPathComponent pathExtension];
if ([lastPathComponent isEqualToString: @"index.eomodeld"] == NO)
{
if ([pathExtension isEqualToString: @"eomodeld"] == NO)
{
searchPath =
[searchPath stringByAppendingPathExtension: @"eomodeld"];
}
searchPath =
[searchPath stringByAppendingPathComponent: @"index.eomodeld"];
}
searchPath = [searchPath stringByStandardizingPath];
if (chkFS==YES)
{
fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath: searchPath] == YES)
{
returnPath = searchPath;
}
else
{
searchPath = path;
if ([pathExtension isEqualToString: @"eomodel"] == NO)
{
searchPath =
[searchPath stringByAppendingPathComponent: @"eomodel"];
}
searchPath = [searchPath stringByStandardizingPath];
if ([fileManager fileExistsAtPath: searchPath] == YES)
{
returnPath = searchPath;
}
}
NSAssert1(returnPath!=nil,@"No valid Model found at path:%@", path);
}
else
{
returnPath = searchPath;
}
lastPathComponent = [returnPath lastPathComponent];
if ([lastPathComponent isEqualToString: @"index.eomodeld"] == YES)
{
returnPath = [returnPath stringByDeletingLastPathComponent];
}
return returnPath;
}
- (EOEntity *) _verifyBuiltEntityObject: (id)entity
named: (NSString*)name
{
if ([entity isKindOfClass: [EOEntity class]] == NO)
{
[EOObserverCenter suppressObserverNotification];
NS_DURING
{
NSString *basePath = nil;
NSString *plistPathName = nil;
NSDictionary *propList = nil;
EOFLOGObjectLevelArgs(@"gsdb", @"name=%@", name);
if (!name && [entity isKindOfClass: [NSDictionary class]])
name = [entity objectForKey: @"name"];
EOFLOGObjectLevelArgs(@"gsdb", @"name=%@", name);
NSAssert1(name, @"No name for entity %@", entity);
EOFLOGObjectLevelArgs(@"gsdb", @"[self path]=%@", [self path]);
basePath = [self path];
AUTORELEASE(RETAIN(entity)); //so it won't be lost in _removeEntity
EOFLOGObjectLevelArgs(@"gsdb", @"basePath =%@", basePath);
if ([basePath hasSuffix: @"eomodel"])
{
propList = entity;
}
else
{
plistPathName = [[basePath stringByAppendingPathComponent: name]
stringByAppendingPathExtension: @"plist"];
EOFLOGObjectLevelArgs(@"gsdb", @"entity plistPathName =%@",
plistPathName);
propList
= [NSDictionary dictionaryWithContentsOfFile: plistPathName];
EOFLOGObjectLevelArgs(@"gsdb", @"entity propList=%@", propList);
if (!propList)
{
if ([[NSFileManager defaultManager]
fileExistsAtPath: plistPathName])
{
NSAssert1(NO,
@"%@ is not a dictionary or is not readable.",
plistPathName);
}
else
{
propList = entity;
NSWarnLog(@"%@ doesn't exists. Using %@",
plistPathName, propList);
}
}
}
[self _removeEntity: entity];
EOFLOGObjectLevelArgs(@"gsdb", @"entity propList=%@", propList);
entity = [self _addEntityWithPropertyList: propList];
}
NS_HANDLER
{
[EOObserverCenter enableObserverNotification];
[localException raise];
}
NS_ENDHANDLER;
[EOObserverCenter enableObserverNotification];
}
return entity;
}
/*
This method rebuilds the caches:
_entitiesByName, _subEntitiesCache, _entitiesByClass
from _entities. Insure this works for real entities and dictionaries
which could be contained in _entities. Also note that className need
not be unique.
*/
- (void)_updateCache
{
NSArray *names;
EOEntity *entity;
NSString *className;
unsigned int i,c;
DESTROY(_subEntitiesCache);
NSResetMapTable(_entitiesByClass);
names = [_entities valueForKey: @"name"];
DESTROY(_entitiesByName);
_entitiesByName = [[NSMutableDictionary alloc] initWithObjects: _entities
forKeys: names];
for (i = 0, c = [_entities count]; i < c; i++)
{
entity = [_entities objectAtIndex: i]; /* entity or dictionary */
className = [entity valueForKey: @"className"];
NSMapInsertIfAbsent(_entitiesByClass, className, entity);
}
}
@end /* EOModel (EOModelPrivate) */