Why I do Open Source
(This was inspired by Andres Almiray)
I did not have a lot of exposure to Open Source software during my formative computing years. I come from a Classic Mac OS (I saw the last few releases of 7) background and was blissfully ignorant to Linux. The move to OS X exposed me to a plethora of previously unavailable software and during this time I was becoming interested in coding. As a student surrounded by other “Computer Scientists” who were interested in anything but coding, my only real available avenue for growth was to participate in virtual communities of developers.
While it wasn't an intentional move, the ideals and general culture of typical open source developer communities resonate very naturally with me (open information, need before greed etc). Also, I am attracted to the artistic side of writing software as opposed to just being in it for the utility. In my experience (which granted isn't vast) you can find extremely talented people who are true artists, not just laborers, gathered around open source projects. If you are putting your work up in front of these people then you are forcing yourself to improve, and to me that is what it's about.
I am sure not all Open Source Software is of a high calibre, but I bet you that in almost every case that man hour for man hour an open source project will trump a closed commercial project in terms of quality almost every time. If you want to improve your skills, hang out with the best around.
Apart from this self interested reason, I also enjoy creating software that other people use. There is not much better than getting an email from someone you don't know and them thanking you for the hours you put into something because it has helped them achieve something.
12:20 PM | 0 CommentsGldapo Validation
I am about to commit the new GORM inspired validation mechanism to Gldapo. Here is what it is going to look like…
Declaring your constraints
Instead of a DSL like GORM, we are using annotations…
import gldapo.schema.annotations. class Person { @GldapoNamingAttribute String uid @Required String sn @Required @Matches(/[A-Z]./) String givenName }
Plugging in your own constraints
You can register your own constraints quite easily. There are two parts, the constraint annotation and the validator.
The constraint annotation (has to be in Java since you can't define annotations in Groovy 1.5.x)…
import java.lang.annotation.*; import gldapo.schema.annotation.Validator; import gldapo.schema.attribute.validator.EqualsValidator; @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Validator(EqualsValidator) // <-- define what can validate this type of constraint public @interface Equals { Object value(); }
As you can see it's a stock standard annotation, that is itself annotated with @Validator to tell Gldapo how to validate this type of constraint.
The validator looks like this…
package gldapo.schema.attribute.validator class EqualsValidator extends AbstractFieldValidator { def validate(obj) { if (obj != this.constraint.value()) { return ['notequals', "notequals.${this.constraint.value()}"] } } }
Validators have to extend gldapo.schema.attribute.validator.AbstractFieldValidator and implement validate(obj). This method takes the value to validate and returns either a single error code, or a list of error codes. If the value is valid it should return null.
Gldapo will register several error codes if validation fails. If a class called Person has it's name field annotated with @Equals('Luke') and it fails validation, the following error codes will be registered…
notequals
notequals.Luke
person.notequals
person.notequals.Luke
person.name.notequals
person.name.notequals.Luke
If the usage of error codes seem a bit weird here, then you should check out 7.4 Validation and Internationalization in the Grails user guide as the concept is exactly the same.
Finally, you need to register your constraint with Gldapo. You do this by listing your custom constraint types as a list under the contraintTypes key in the config…
Gldapo.initialize( contraintTypes: [Equals] )
Performing validation
This side of things works exactly like GORM…
def p = new Person(uid: "ld", givenName: "Luke" sn: "Daley") if (!p.save()) { p.errors.allErrors.each { println it } }
There is also the validate() method if you just want to perform validation without trying to write the object back.
If you haven't used validation in GORM, check out this chapter in the user guide, because it will all hold true (except how constraints are defined) with Gldapo.
11:52 AM | 0 Comments | Tags: gldapo, groovy, grailsGrails TextMate bundle is being improved
I am working on a grails app (more info to come), as such I am making some long needed improvements to the Grails TextMate bundle. If you are using this, you might want to subscribe to the bundle changes feed.
I have made two changes already; a snippet for the <g:render> tag in GSPs, and a command to run a single test case (the currently open file in TM).
Gldapo 0.7.1 Released
This release has only one change which fixes an issue with password attributes.
11:52 AM | 0 Comments | Tags: gldapo, groovyGldapo 0.7 Released
Gldapo 0.7 (and a corresponding grails plugin) is now available.
This release primarily fixes some bugs with password attributes and brings the following major features/improvements:
- The addition of an LDAP filter DSL (thanks to Siegfried Puchbauer)
- Drastic improvement to the API for creating and moving objects.
- JavaDoc for commonly used classes (thanks to new GMaven features)
Release Notes
Sub-task
- [GLDP-66] - Base the location of entries in the directory on a ‘parent’ directiory rather than the ‘rdn’ attribute
- [GLDP-69] - Make defining a naming attribute mandatory (i.e. throw exception if none defined)
- [GLDP-70] - Add documentation for @GldapoNamingAttribute
- [GLDP-79] - Raise exception if rdn is set with a different naming attribute
- [GLDP-82] - Raise exception if naming attribute is changed directly (i.e. not via move() or replace())
- [GLDP-86] - Create ‘GldapoEntry’ abstract base class and document
Bug
- [GLDP-76] - Converting raw array values to native (groovy) values with schema-custom mapper raises GldapoTypeMappingException
- [GLDP-77] - Reading an entry with a password attribute raises exceptions
- [GLDP-81] - Static properties on schemas are not ignored
- [GLDP-91] - GldapoSynonymFor breaks GldapoNamingAttribute
Improvement
- [GLDP-47] - When moving/replacing an object, the in memory value of the naming attribute should be updated to reflect the change
- [GLDP-58] - Fix JavaDoc generation and use that as the definitive documentation source
- [GLDP-60] - Sanitise API for replacing/moving objects
- [GLDP-72] - Consolidate overloaded rdn setter on schema objects
- [GLDP-73] - Fetch raw values from contexts as objects, not strings
- [GLDP-74] - Implement tests for schema-custom TO FIELD type mappers
- [GLDP-75] - Implement tests for schema-custom TO TYPE type mappers
- [GLDP-87] - Rename ‘rdn’ property to ‘brdn’
New Feature
- [GLDP-41] - Provide way to name object based on particular attribute
- [GLDP-68] - Add a Filter DSL to ease LDAP querying
- [GLDP-71] - Support password type attributes
- [GLDP-78] - Add ‘namingValue’ property to entries
- [GLDP-83] - Add move(String,Object) method to move an object by naming value and parent
- [GLDP-84] - Add replace(String,Object) method to replace an object by naming value and parent
- [GLDP-85] - Add replace() method
- [GLDP-89] - Provide find() and findAll() variants that take a filter builder closure
- [GLDP-90] - Typemapping for Boolean type
Enjoy.
03:29 PM | 0 Comments | Tags: gldapo, groovy