LDAPEOAdaptor.framework: 10/12/98 created by Ryan Krebs, with some help from Luke Howard and Joe Little. This library and its source are covered by the GNU LGPL. See the file LGPL.txt for more info. Currently this framework is in the beta stage of its development, and all the usual warnings come with it. I can't guarantee support and all that stuff. Lately I've been focusing on other projects, so I'll only have a limited amount of time to work on the adaptor, but feel free to send comments. I'll get to them as soon as I can. I can be reached at rkrebs@cisnet.stanford.edu (don't worry, that address is scattered all over the place here). This was my first project with Objective C, the first time I've used WebObjects and EOF, and a lot of other firsts for me. Apple also could have done a better job documenting how to *make* an EOAdaptor, instead of just programming using an existing one (no offense guys), but I think I picked up on most of it. All that being said, here's what it does: ****************** EOModel generation ****************** - The EOAdaptor will perform a base-scope search for (objectclass=subschema) at the search base of your choosing (you can specify it in the login panel under "schema base", default is "cn=schema"). With Netscape's Directory Server, this returns a single entry with lots of schema information. With UMich's implementation, it may return nothing, unless you put something there. You don't really *need* anything there, you just can't have EOModeler generate a model for you without it. If you're using the UMich server and want to put schema information someplace, make sure it's the right format: objectclasses: ( oid NAME 'name' [ DESC 'desc' ] [ SUP 'parent' ] [ MUST ( must1 $ must2 & etc ) ] [ MAY ( may1 $ may2 $ etc ) ] ) attributetypes: ( oid NAME 'name' [ DESC 'desc' ] SYNTAX 'syntax-oid' ) - The entry returned is parsed for a list of objectclasses and attributetypes. You can choose which objectclasses to include in the model, and the EOAdaptor will construct a table for each of those objectclasses. - If an entry exists for a certain attributetype, and the syntax is recognized as something that should be binary, EOModeler will set the class for that attribute to NSData, otherwise it defaults to NSString. - "Allows Null" is set depending on whether an attribute is listed under "MUST" or "MAY". - I added two relationships: "toChildren" and "toParent", based on the DNs of the entries. This was part of planning for something where one could move up and down the tree in WebObjects, although I haven't implemented anything like this yet and may just remove it entirely. - I also added a couple attributes: dn, rdn, and parent. (Hopefully nobody will want to use an attribute named "parent" in their schema, but I suppose I can change this, or have a place to customize it.) dn is, of couse, the DN, and is also set as the primary key. rdn is the RDN of the entry. Changes to the value of RDN in WebObjects result in a call of ldap_modrdn2() to change the RDN. parent is the DN of the parent entry, is generated by exploding the dn of the entry and reassembling the pieces, and is used in the relationships toChildren and toParent. Any changes to the value of parent in WebObjects are ignored. *************** Searching in WO *************** - I added a couple of methods to the EOQualifier subclasses to generate LDAP search strings. The main one is the EOKeyValueQualifier, which returns a string with the format "(key=value)". There's a *slight* problem here in that the key matches the EOAttribute's name, and not the column name, which is what really needs to be in the search string. The EO{And, Or, Not}Qualifier classes build the more complex filters; (!(key=value)(key=value)), (|(key=value)(key=value)), etc. The EOFetchSpecification tacks on an objectclass=entityname at the beginning of the filter, to ensure you only get entries that belong in your model. - When entries are returned, they're parsed into NSDictionary objects with the attribute name as key, and an NSString or NSData object for the value. - When an attribute has multiple values, the adaptor pulls a "valuesJoinedByString:" on the array, to make it a single value. (WebObjects didn't seem to like arrays too much... Maybe it's just me.) - If an attribute specified by attributesToFetch: does not exist in the entry, then an empty string is set for the value to avoid problems with snapshotting. ************** Deleting in WO ************** - When you delete an entry in WebObjects, the adaptor has to perform a search for the entries matching the qualifier WO passes it. Then it can obtain the DN of the entry and deletes it through ldap_delete(). *************** Modifying in WO *************** - Changes to a value in WebObjects are translated into an LDAPMod structure to be used in ldap_modify(). - An attribute that containes multiple values that were joined earlier is separated into those values for the modification. - Changes to the rdn attribute are caught and sent to ldap_modrdn2(). - Attributes changed to an empty string are deleted from the entry. ************ Adding in WO ************ - New entries can be created through WebObjects, but each attribute has to at least have an empty string for a value (not NULL), or else WO complains about encoding NULL. You can set up default behavior in the WO application for new values to be set to @"". *********** Other stuff *********** - There are lots of little things that haven't been tested much, if at all. (Things like binary attributes and alternate methods of authentication. If you find something that doesn't work the way you think it should, e-mail me (rkrebs@cisnet.stanford.edu). - I've started out using one of the UMich LDAP libraries, with the Netscape Directory Server, on an NT box. Later I switched to the Netscape LDAP library, which seems to be working a little better. I've also compiled under Solaris 2.6 with the Netscape library, which seems to work fine. There may be little things that work perfectly well with this setup, but not at all with others. Again, please let me know if something doesn't work right. ********************* Problems I know about ********************* - When a new entry is created, WO leaves the values as EONull if you don't change them, and then complains about encoding when you try to save them. You can set the default values of new attributes to @"" in the WO application to fix this. - Search filters are generated based on attribute name, not column name. This is because the EOKeyValueQualifier only stores the attribute name, not a whole EOAttribute, which would allow me to get the column name. I'm not sure how to get around this, other than making sure your column names and attribute names match. - Attributes with the ;binary suffix in their name. These are currently ignored, because EOF won't allow ;s in attribute names. They're just fine in the column names, but otherwise aren't allowed. The discrepancy in the names causes problems with snapshotting, so entries containing these attributes can't be modified. Thus those attributes are ignored by the EOAdaptor. - There's a problem with WOBuilder that I've been having... When it parses Main.h for instance variables it might not pick up on everything. If you have // style comments, as opposed to /* */ style comments, it will ignore everything until the next ; on a following line. Everything will run fine until you try saving your Main.wo in WOBuilder, at which point it will forget to put certain declarations in Main.woo (those following the // comments). I've informed Apple and they will hopefully have this fixed soon. If you're not having this problem, I'd be interested to hear from you (I'm using WebObject 3.5 Academic on NT). ************ Suggestions? ************ I whole-heartedly welcome any questions or suggestions for improvement. You can e-mail me at rkrebs@cisnet.stanford.edu. Don't hesitate to tell me I'm doing it all wrong :) *********** Thank you!! *********** Thank you for reading this far. Thanks also to Luke Howard for his help with pointers (nasty little devils), and Joe Little for giving me the opportunity to do this stuff, and of course Apple for delivering the great products. (You can have your name here too if you fix/report any bugs.)