W poprzednim wpisie przedstawiłem sposób na redukcję kodu w encjach przy pomocy dziedziczenia i adnotacji @MappedSuperclass. Rozwiązanie to możemy również stosować aby tworzyć kod bardziej przenośny, który niewielkim kosztem można użyć w innych projektach.

Większość aplikacji webowych stosuje autoryzację opartą o role (ang. Role Based Access Control), w takich wypadkach mamy zazwyczaj encję User oraz Role, pierwszą odpowiedzialną za przetrzymywanie informacji o użytkowniku a druga nazwy ról. O ile role są obszarem stałym - zawsze mają nazwę - o tyle użytkownicy często mają różne wariacje i relacje. Ot choćby powiązanie konta użytkownika z firmą. [sourcecode lang=“java”] // Copyright (C) 2009 Code-House // All rights reserved package org.code_house.security.domain;

import java.util.Calendar; import java.util.HashSet; import java.util.Set;

import javax.persistence.Column; import javax.persistence.ManyToMany; import javax.persistence.MappedSuperclass; import javax.persistence.Temporal; import javax.persistence.TemporalType;

import org.code_house.domain.BaseEntity;

/\\ \* Klasa reprezentująca użytkownika. Powinna ona zostać nadpisana w docelowym \* systemie poprzez plik orm.xml. \* \* @author Łukasz Dywicki. */ @MappedSuperclass public class SecurityUser extends BaseEntity {

/\\ \* Hasło użytkownika. */ @Column private String password;

/\\ \* Login użytkownika. */ @Column private String username;

/\\ \* Konto wygasło. */ @Column @Temporal(TemporalType.TIMESTAMP) private Calendar expire;

/\\ \* Grupy do których przynależy użytkownik. */ @ManyToMany(mappedBy = “users”) private Set roles;

/\\ \* Konto zablokowane np. po 3 nieudanych próbach logowania. */ @Column private boolean locked;

/\\ \* Konto wyłączone np. przez administratora. */ @Column private boolean enabled;

// Dalej gettery i settery } [/sourcecode] Rola ma niekompletną definicję relacji do klasy SecurityUser, którą należy uzupełnić o informacje na temat encji docelowej i definicji tabeli pośredniczącej. [sourcecode lang=“java”] // Copyright (C) 2009 Code-House // All rights reserved package org.code_house.security.domain;

import javax.persistence.Entity; import javax.persistence.ManyToMany; import javax.persistence.Table;

import org.code_house.domain.NamedEntity;

/\\ \* Klasa reprezentująca rolę. Może to być np ADMIN, USER bądź cokolwiek innego. \* \* @author Łukasz Dywicki luke@code-house.org */ @Entity @Table(name = “roles”) public class Role extends NamedEntity {

@ManyToMany @JoinTable(name = “users_roles”, joinColumns = @JoinColumn(name = “role_id”, referencedColumnName = “id”) ) private Set users;

// gettery i settery } [/sourcecode] Oto kawałek konfiguracji XML, która uzupełni metadane i pozwoli na uruchomienie kodu. Atrybut target-entity pozwala na określenie tabeli docelowej relacji podczas gdy element inverse-join-column uzupełnia definicję tabeli pośredniczącej. [sourcecode lang=“xml” classname=“xml”]

org.code_house.security.domain

\[/sourcecode\]

Przykład ten można wykorzystać by uzupełniać relacje, których nie sposób odzwierciedlić w kodzie.