Monday, May 5, 2008

EOGlobalIDs for Abstract Entities

I just got burned by this and it was a bitch to figure out. I had an ERXBatchingDisplayGroup that was fetching an abstract entity type that used Single Table Inheritance. It turns out that the way ERXBDG was fetching, it fetched the page of PK's, turned those into faults, then fired the faults. The problem with this is that if you turn a PK into a fault for an abstract entity type (note that it just has the PK, so it doesn't know the actual subentity yet), EOF decides to fetch the object so it can resolve the entity name for the global id. You'll see this as a bunch of one-by-one fetches in your log. Needless to say this is total crap.

It turns out that you can instead turn each PK into a GID directly with entity.globalIDForRow(pkDict). Inside of EOGlobalID, it already tracks the concept of not knowing the final subclass type. When you attempt to turn this global ID into an EO (using ERXGlobalIDUtilities, or whatever), EOF will properly fetch the objects and everyone will be happy. The nice thing here is that ERXGIDUtils can batch those fetches into a single query so you don't get 40, 50, 100 (or whatever your page size is) hits to the DB. This SEEMS like a bug in EOF to me, though I won't say that this won't totally burn me at some point. (by "me," I mean "all of us" since this has now been changed in ERXBatchingDisplayGroup).

Wednesday, April 23, 2008

ActiveLDAP

ActiveLDAP has some annoying install warts, but it's a pretty cool library.

Installing

First download and build RubyLDAP. Annoyingly this is NOT a gem, so you can't gem install it.

Next, build it ...
ruby extconf.rb
make
sudo make install

Now install ActiveLDAP ...

sudo gem install ruby-activeldap
Quick Start

Many of the examples are talking to a default openldap install. If you want to talk to a Mac OS X Open Dircetory server, you will need to change the prefix for users and groups, shown below in a quick sample app:

#!/usr/bin/env ruby

require 'rubygems'
require 'active_ldap'

class Group < ActiveLdap::Base
  ldap_mapping :dn_attribute => 'cn',
               :prefix => 'cn=groups',
               :classes => ['top', 'posixGroup'],
               :scope => :one
  has_many :members,
           :class => "User",
           :wrap => "memberUid",
           :primary_key => 'uid'
end

class User < ActiveLdap::Base
  ldap_mapping :dn_attribute => 'uid',
               :prefix => 'cn=users',
               :classes => ['top','inetOrgPerson']
  belongs_to :groups,
             :class => 'Group',
             :many => 'memberUid'
end

ActiveLdap::Base.establish_connection(
  :host => 'someldapserver.mdimension.com',
  :port => 389,
  :base => 'dc=mdimension,dc=com',
  :bind_dn => "uid=mschrag,cn=mdimension,dc=com",
  :password => 'mschragpw',
  :allow_anonymous => false,
  :try_sasl => false
)

#Group.find(:all, '*').each do |group|
  #puts "#{group.cn}"
  #group.members.each do |member|
    #puts "  #{member.cn}"
  #end
#end

user = User.find('mschrag');
user.givenName = 'NewFirstName'
user.save
And that's the quick start. It should give you enough to experiment with.

Saturday, March 29, 2008

git-cvsimport failure

I've been mirroring Project Wonder's CVS with github, and unfortunately git-cvsimport has been a real problem. If I try to run it directly on the repository, I get:

git-cvsimport: fatal: cvsps reported error 11

... which is really helpful. Well it turns out that you can run cvsps outside of git-cvsimport and get this all to work. Here's roughly what you need to do:

export CVSROOT=[your cvsroot]
cvsps -x --norc -u -A [your cvsmodule] > /tmp/cvsps.out
cd /path/to/your/git/repos
git-cvsimport -o git_cvs_head_branch_name -P /tmp/cvsps.out [your cvsmodule]
So in my case, I do:
export CVSROOT=/local/wonder/cvs
cvsps -x --norc -u -A Wonder > /tmp/cvsps.out
cd /local/wonder/git
git-cvsimport -o Wonder_HEAD_Branch -P /tmp/cvsps.out Wonder

The key here is that we run cvsps manually, saving its output, then run git-cvsimport with a -P passing it the name of the cvsps output. This allows us to manually ignore cvsps errors rather than have them kill git-cvsimport.

Note that by default gitcvs-import will use "master" as your head branch, which can cause problems with later merges. It's best to keep all CVS branches in their own git branch and don't touch them except with git-cvsimport.

VS 2008

Visual Studio 2008 has some really slick features ... Check out the Javascript interpreter stuff in particular. I plan to steal liberally from this for WOLips.

Handy shell things

stick these in your ~/.bash_profile:
alias grep='grep --color=auto'
function ps() {
 /bin/ps $* | sed -E $'s#[0-9]+#\e[31m&\e[0m#'
}
The grep one will make your grep matches change color, which makes it a lot easier to find in a line. The ps one makes the pid turn red, which is really useful if you have processes with really long commandlines (like a WO app):

LDAP EOF Adaptor

A word of warning if you're working with LDAP/JNDI and creating EOModels on them. LDAP supports multi-value attributes, which means you could have, for instance, multiple "uid"'s (Apple provides for multiple "short names", for instance). In your EOModel, you should be careful about how you define the types of these values. If there is one value, it will return a String. If there are multiple values, it will return an NSArray, so you should declare the value type to be "java.lang.Object" and check for what you're getting back when you call the method.

Apache Directory Studio

Apache Directory Studio -- actually "just worked" and is even sort of nice (I mean, for an Eclipse-based app). Totally shocked. So if you need an LDAP browser, check it out.