Tuesday, July 31, 2007

Linux : the more you know ...

I'm somewhat embarrassed to admit this, but I've just discovered Linux ACLs, which are apparently in every kernel 2.6+, and has plugins for 2.4-. I guess a really linux savvy person should know these, especially since they're incredibly useful and give so so much more power over the default User - Group - World permissions built into the file system.

Friday, July 27, 2007

JSP Tags

They're oh so useful for encapsulating small bits of reusable logic, but, here's the kicker : when they're compiled, only one instance of a tag is generated for a given page, so you have to design them to be stateful and ensure that you override the 'release' method when inheriting from TagSupport or BodyTagSupport. It took me a couple of hours to figure this out, and sadly, it was for the second time. I guarantee there won't be a third after this.

Wednesday, July 04, 2007

Moar (sic) Hibernate

OK, so once again in my (seemingly never-ending) struggle with Hibernate, I have stuff to report that's mainly being posted here for my own reading so that I can reference this shit later. This time, I've decided to abandon Xdoclet and just go with Annotations. They're so much easier and I don't have to deal with Xdoclet's quirks any more (like ridiculous parsing exceptions between versions).

If you want to use annotations to do a bidirectional OneToMany assocation with list-based semantics, here's the annotations you use :

Parent.java (equals, hashCode, getters/setters removed for clarity):
@Entity
@Table(name = "parent")
public class Parent implements Serializable {

private static final long serialVersionUID = -1989884660562516228L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;

@Column(name = "name")
private String name;

@OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade = {CascadeType.ALL})
@Cascade({org.hibernate.annotations.CascadeType.ALL,org.hibernate.annotations.CascadeType.DELETE_ORPHAN})
@IndexColumn(name = "idx", nullable = false)
private List children;
}


Child.java (equals, hashCode, getters/setters removed for clarity):
@Entity
@Table(name = "child")
public class Child implements Serializable {
private static final long serialVersionUID = -6414526385302360120L;

@Id
@Column(name = "id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "name")
private String name;

@ManyToOne
@JoinColumn(name = "parent_id")
private Parent parent;

@Column(name = "idx")
private int index;

public Child() {
super();
}

public int getIndex() {
return this.parent.getChildren().indexOf(this);
}

public void setIndex(int index) {
}
}

Note that you need the 'index' pseudo-property in the child class in order for hibernate to properly persist the ordering of the elements in the collection. The setter for the index property should do nothing, the getter should determine the object's placement in its parent, and you'll need the field with annotations in order to get hibernate to read everything properly. The name of the column in the annotation for the index property MUST be the same as that specified in the parent in the @IndexColumn property. They aren't very clear about this in the Hibernate Documentation (once again.) They mention a similar structure for the .hbm.xml mappings in a faq on the main site for hibernate (not the hibernate annotations faq), but they don't explicitly mention this anywhere for Annotations. You can read the mention of it for .hbm.xml files here. I'm sure I'll have to post more about annotation configurations later, but that's all for now. And if you're wondering, the misspelling in the title of this post is an inside joke.

PS. Note that in addition to the OneToMany and IndexColumn annotations on the child collection in the parent, you also need to have a @Cascade annotation in order to properly remove orphans from the database when deleting children from the child collection in the parent. You can also find the table that gave me my final clues on Darren Hicks' blog