XML i Adnotacje – kod ogólnego przeznaczenia i JPA

1 Paź
2009

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ą.

// 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<Role> 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
}

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.

// 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<SecurityUser> users;

    // gettery i settery
}

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.

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0" 
        xmlns="http://java.sun.com/xml/ns/persistence/orm"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">

    <package>org.code_house.security.domain</package>

    <entity class="Role">
        <attributes>
            <many-to-many name="users" target-entity="org.code_house.management.domain.User">
                <join-table>
                    <inverse-join-column name="user_id" referenced-column-name="id" />
                </join-table>
            </many-to-many>
        </attributes>
    </entity>
    <entity class="Memento">
        <attributes>
            <one-to-one name="user" target-entity="org.code_house.management.domain.User">
                <join-column name="user_id" />
            </one-to-one>
        </attributes>
    </entity>
</entity-mappings>

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

Comment Form

You must be logged in to post a comment.

top