RSS Feed for This PostCurrent Article

Design of a Java Application Framework Part 1 – Model Layer

I have been using AppFuse in several projects. It is a excellent framework which implemented a proper MVC architecture.

In order to better understand the framework, I spent sometime browsing through the source code, I also tried looking for some local SEO services where I could help fast.

In Part I of this articles I am going to show you the model layer.

For all the model classes in AppFuse, it has to extends BaseObject, which has the abstract methods toString, equals and hashCode. Note that BaseObject implements Serializable

 

/**

 * Base class for Model objects. Child objects should implement toString(),

 * equals() and hashCode().

 */

public abstract class BaseObject implements Serializable {    

 

    /**

     * Returns a multi-line String with key=value pairs.

     * @return a String representation of this class.

     */

    public abstract String toString();

 

    /**

     * Compares object equality. When using Hibernate, the primary key should

     * not be a part of this comparison.

     * @param o object to compare to

     * @return true/false based on equality tests

     */

    public abstract boolean equals(Object o);

 

    /**

     * When you override equals, you should override hashCode. See "Why are

     * equals() and hashCode() importation" for more information:

     * http://www.hibernate.org/109.html

     * @return hashCode

     */

    public abstract int hashCode();

}

All model classes shall extends BaseObject and have Java annotation to include additional information on the class and the properties relating to database.

E.g. for User model class

 

/**

 * This class represents the basic "user" object in AppFuse that allows for authentication

 * and user management.  It implements Acegi Security's UserDetails interface.

 *

 */

@Entity

@Table(name="app_user")

public class User extends BaseObject implements Serializable, UserDetails {

    private static final long serialVersionUID = 3832626162173359411L;

 

    private Long id;

    private String username;                    // required

    private String password;                    // required

    private String confirmPassword;

    private String passwordHint;

    private String firstName;                   // required

    private String lastName;                    // required

    private String email;                       // required; unique

    private String phoneNumber;

    private String website;

    private Address address = new Address();

    private Integer version;

    private Set<Role> roles = new HashSet<Role>();

    private boolean enabled;

    private boolean accountExpired;

    private boolean accountLocked;

    private boolean credentialsExpired;

 

    /**

     * Default constructor - creates a new instance with no values set.

     */

    public User() {}

 

    /**

     * Create a new instance and set the username.

     * @param username login name for user.

     */

    public User(final String username) {

        this.username = username;

    }

 

    @Id @GeneratedValue(strategy=GenerationType.AUTO)

    public Long getId() {

        return id;

    }

 

    @Column(nullable=false,length=50,unique=true)

    public String getUsername() {

        return username;

    }

 

    @Column(nullable=false)

    public String getPassword() {

        return password;

    }

 

    @Transient

    public String getConfirmPassword() {

        return confirmPassword;

    }

 

    @Column(name="password_hint")

    public String getPasswordHint() {

        return passwordHint;

    }

 

    @Column(name="first_name",nullable=false,length=50)

    public String getFirstName() {

        return firstName;

    }

 

    @Column(name="last_name",nullable=false,length=50)

    public String getLastName() {

        return lastName;

    }

 

    @Column(nullable=false,unique=true)

    public String getEmail() {

        return email;

    }

 

    @Column(name="phone_number")

    public String getPhoneNumber() {

        return phoneNumber;

    }

 

    public String getWebsite() {

        return website;

    }

 

    /**

     * Returns the full name.

     * @return firstName + ' ' + lastName

     */

    @Transient

    public String getFullName() {

        return firstName + ' ' + lastName;

    }

 

    @Embedded

    public Address getAddress() {

        return address;

    }

 

    @ManyToMany(fetch = FetchType.EAGER) 

    @JoinTable(

            name="user_role",

            joinColumns = { @JoinColumn( name="user_id") },

            inverseJoinColumns = @JoinColumn( name="role_id")

    )    

    public Set<Role> getRoles() {

        return roles;

    }

 

    /**

     * Convert user roles to LabelValue objects for convenience.

     * @return a list of LabelValue objects with role information

     */

    @Transient

    public List<LabelValue> getRoleList() {

        List<LabelValue> userRoles = new ArrayList<LabelValue>();

 

        if (this.roles != null) {

            for (Role role : roles) {

                // convert the user's roles to LabelValue Objects

                userRoles.add(new LabelValue(role.getName(), role.getName()));

            }

        }

 

        return userRoles;

    }

 

    /**

     * Adds a role for the user

     * @param role the fully instantiated role

     */

    public void addRole(Role role) {

        getRoles().add(role);

    }

    

    /**

     * @see org.springframework.security.userdetails.UserDetails#getAuthorities()

     * @return GrantedAuthority[] an array of roles.

     */

    @Transient

    public GrantedAuthority[] getAuthorities() {

        return roles.toArray(new GrantedAuthority[0]);

    }

 

    @Version

    public Integer getVersion() {

        return version;

    }

    

    @Column(name="account_enabled")

    public boolean isEnabled() {

        return enabled;

    }

    

    @Column(name="account_expired",nullable=false)

    public boolean isAccountExpired() {

        return accountExpired;

    }

    

    /**

     * @see org.springframework.security.userdetails.UserDetails#isAccountNonExpired()

     */

    @Transient

    public boolean isAccountNonExpired() {

        return !isAccountExpired();

    }

 

    @Column(name="account_locked",nullable=false)

    public boolean isAccountLocked() {

        return accountLocked;

    }

    

    /**

     * @see org.springframework.security.userdetails.UserDetails#isAccountNonLocked()

     */

    @Transient

    public boolean isAccountNonLocked() {

        return !isAccountLocked();

    }

 

    @Column(name="credentials_expired",nullable=false)

    public boolean isCredentialsExpired() {

        return credentialsExpired;

    }

    

    /**

     * @see org.springframework.security.userdetails.UserDetails#isCredentialsNonExpired()

     */

    @Transient

    public boolean isCredentialsNonExpired() {

        return !credentialsExpired;

    }

    

    public void setId(Long id) {

        this.id = id;

    }

    

    public void setUsername(String username) {

        this.username = username;

    }

 

    public void setPassword(String password) {

        this.password = password;

    }

 

    public void setConfirmPassword(String confirmPassword) {

        this.confirmPassword = confirmPassword;

    }

 

    public void setPasswordHint(String passwordHint) {

        this.passwordHint = passwordHint;

    }

 

    public void setFirstName(String firstName) {

        this.firstName = firstName;

    }

 

    public void setLastName(String lastName) {

        this.lastName = lastName;

    }

 

    public void setEmail(String email) {

        this.email = email;

    }

 

    public void setPhoneNumber(String phoneNumber) {

        this.phoneNumber = phoneNumber;

    }

 

    public void setWebsite(String website) {

        this.website = website;

    }

 

    public void setAddress(Address address) {

        this.address = address;

    }

 

    public void setRoles(Set<Role> roles) {

        this.roles = roles;

    }

 

    public void setVersion(Integer version) {

        this.version = version;

    }

    

    public void setEnabled(boolean enabled) {

        this.enabled = enabled;

    }

 

    public void setAccountExpired(boolean accountExpired) {

        this.accountExpired = accountExpired;

    }

    

    public void setAccountLocked(boolean accountLocked) {

        this.accountLocked = accountLocked;

    }

 

    public void setCredentialsExpired(boolean credentialsExpired) {

        this.credentialsExpired = credentialsExpired;

    }

    

    /**

     * {@inheritDoc}

     */

    public boolean equals(Object o) {

        if (this == o) {

            return true;

        }

        if (!(o instanceof User)) {

            return false;

        }

 

        final User user = (User) o;

 

        return !(username != null ? !username.equals(user.getUsername()) : user.getUsername() != null);

 

    }

 

    /**

     * {@inheritDoc}

     */

    public int hashCode() {

        return (username != null ? username.hashCode() : 0);

    }

 

    /**

     * {@inheritDoc}

     */

    public String toString() {

        ToStringBuilder sb = new ToStringBuilder(this, ToStringStyle.DEFAULT_STYLE)

                .append("username", this.username)

                .append("enabled", this.enabled)

                .append("accountExpired", this.accountExpired)

                .append("credentialsExpired", this.credentialsExpired)

                .append("accountLocked", this.accountLocked);

 

        GrantedAuthority[] auths = this.getAuthorities();

        if (auths != null) {

            sb.append("Granted Authorities: ");

 

            for (int i = 0; i < auths.length; i++) {

                if (i > 0) {

                    sb.append(", ");

                }

                sb.append(auths[i].toString());

            }

        } else {

            sb.append("No Granted Authorities");

        }

        return sb.toString();

    }

}

Name queries can also be included in the model class. E.g. for the Role class

**

 * This class is used to represent available roles in the database.

 *

 */

@Entity

@Table(name="role")

@NamedQueries ({

    @NamedQuery(

        name = "findRoleByName",

        query = "select r from Role r where r.name = :name "

        )

})

public class Role extends BaseObject implements Serializable, GrantedAuthority {

    private static final long serialVersionUID = 3690197650654049848L;

    private Long id;

    private String name;

    private String description;

 

    /**

     * Default constructor - creates a new instance with no values set.

     */

    public Role() {

    }

 

    /**

     * Create a new instance and set the name.

     * @param name name of the role.

     */

    public Role(final String name) {

        this.name = name;

    }

 

    @Id  @GeneratedValue(strategy=GenerationType.AUTO)

    public Long getId() {

        return id;

    }

 

    /**

     * @see org.springframework.security.GrantedAuthority#getAuthority()

     * @return the name property (getAuthority required by Acegi's GrantedAuthority interface)

     */

    @Transient

    public String getAuthority() {

        return getName();

    }

 

    @Column(length=20)

    public String getName() {

        return this.name;

    }

 

    @Column(length=64)

    public String getDescription() {

        return this.description;

    }

 

    public void setId(Long id) {

        this.id = id;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public void setDescription(String description) {

        this.description = description;

    }

 

    /**

     * {@inheritDoc}

     */

    public boolean equals(Object o) {

        if (this == o) {

            return true;

        }

        if (!(o instanceof Role)) {

            return false;

        }

 

        final Role role = (Role) o;

 

        return !(name != null ? !name.equals(role.name) : role.name != null);

 

    }

 

    /**

     * {@inheritDoc}

     */

    public int hashCode() {

        return (name != null ? name.hashCode() : 0);

    }

 

    /**

     * {@inheritDoc}

     */

    public String toString() {

        return new ToStringBuilder(this, ToStringStyle.SIMPLE_STYLE)

                .append(this.name)

                .toString();

    }

 

    public int compareTo(Object o) {

        return (equals(o) ? 0 : -1);

    }

}


Trackback URL


RSS Feed for This Post2 Comment(s)

  1. Affar | Aug 6, 2008 | Reply

    The User class is a child of BaseObject. Also, it implements the Serializable interface.

    WAIT, the BaseObject also implements the Serializable interface !!!!

  2. Caligula | Aug 6, 2008 | Reply

    AppFuse doesn’t implement MVC, AppFuse *uses* an MVC implementation (and even that’s arguable, since it can use Tapestry, which is component-based).

Sorry, comments for this entry are closed at this time.