package auction.model;
import javax.persistence.*;
import java.io.Serializable;
import java.util.*;
/**
* The CaveatEmptor Category can have child categories and each has items.
*
* Categories can be nested, this is expressed as a bidirectional one-to-many
* relationship that references parent and child categories.
*
* Each Category can have many items (and an item can be in many categories). This
* is a many-to-many relationship. There are four strategies how you can map it.
*
* First, the collection items is a true many-to-many association, with
* collections on both sides. There are no additional columns in the underlying
* many-to-many join table.
*
* Second, the collection categorizedItems is a one-to-many association
* to an entity class CategorizedItem that represents the link. The
* Item class has the same collection mapped, to make it bidirectional.
* This intermediate class represents additional columns on the many-to-many
* join table, such as the user who added the item to the category, and the date
* of the addition.
*
* Third, the collection categorizedItemComponents is a collection of
* value typed elements, of value type CategorizedItemComponent. This
* simplifies management of the link (no intermediate entity class) but allows
* only unidirectional navigation. The Item class does not know anything
* about this collection or the components - no shared references.
*
* Finally, the map itemsAndUser represents the many-to-many association
* with a ternary relationship using a hash map. This map has item objects as keys,
* and user objects as values. The underlying many-to-many join table has three
* columns, CATEGORY_ID, ITEM_ID, and ADDED_BY_USER_ID.
* This strategy allows you to map an additional column (the user foreign key) of
* a many-to-many join table without writing an intermediate entity or component
* class.
*
* @see Item
* @see CategorizedItem
* @see CategorizedItemComponent
* @author Christian Bauer
*/
@Entity
@Table(
name = "CATEGORY",
uniqueConstraints =
@UniqueConstraint(columnNames = {"CATEGORY_NAME", "PARENT_CATEGORY_ID"})
// If you want a constraint name in the schema, use in XML instead
)
public class Category implements Serializable, Comparable {
@Id @GeneratedValue
@Column(name = "CATEGORY_ID")
private Long id = null;
@Version
@Column(name = "OBJ_VERSION")
private int version = 0;
@Column(name = "CATEGORY_NAME", length = 255, nullable = false)
private String name;
@OneToMany(mappedBy = "parentCategory", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@org.hibernate.annotations.OrderBy(clause = "CATEGORY_NAME asc")
private List childCategories = new ArrayList(); // A bag with SQL ORDER BY
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_CATEGORY_ID", nullable = true)
@org.hibernate.annotations.ForeignKey(name = "FK_CATEGORY_PARENT_ID")
private Category parentCategory;
@ManyToMany
@JoinTable(
name = "CATEGORY_ITEM",
joinColumns = @JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = @JoinColumn(name = "ITEM_ID")
)
@org.hibernate.annotations.IndexColumn(name = "DISPLAY_POSITION")
@org.hibernate.annotations.ForeignKey(
name = "FK_CATEGORY_ITEM_CATEGORY_ID",
inverseName = "FK_CATEGORY_ITEM_ITEM_ID"
)
@org.hibernate.annotations.Filter(
name = "limitItemsByUserRank",
condition = ":currentUserRank >= (select u.RANK from USERS u where u.USER_ID = SELLER_ID)"
)
private List- items = new ArrayList
- ();
@OneToMany(cascade = CascadeType.ALL, mappedBy = "category")
@org.hibernate.annotations.Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
@org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
private Set categorizedItems = new HashSet();
@org.hibernate.annotations.CollectionOfElements
@JoinTable(
name = "CATEGORIZED_ITEM_COMPONENTS",
joinColumns = @JoinColumn(name = "CATEGORY_ID")
)
@org.hibernate.annotations.ForeignKey(name = "FK_CATEGORIZED_ITEM_COMPONENT_CATEGORY_ID")
private Set categorizedItemComponents = new HashSet();
@ManyToMany
@org.hibernate.annotations.MapKeyManyToMany(
joinColumns = @JoinColumn(name = "ITEM_ID")
)
@JoinTable(
name = "CATEGORY_ITEMS_BY_USER",
joinColumns = @JoinColumn(name = "CATEGORY_ID"),
inverseJoinColumns = @JoinColumn(name = "USER_ID")
)
@org.hibernate.annotations.ForeignKey(
name = "FK_CATEGORY_ITEMS_BY_USER_CATEGORY_ID",
inverseName = "FK_CATEGORY_ITEMS_BY_USER_USER_ID"
// TODO: Can't declare the foreign key constraint name for ITEM_ID...
)
private Map
- itemsAndUser = new HashMap
- ();
@Temporal(TemporalType.TIMESTAMP)
@Column(name="CREATED", nullable = false, updatable = false)
private Date created = new Date();
/**
* No-arg constructor for JavaBean tools
*/
public Category() {}
/**
* Full constructor
*/
public Category(String name,
List childCategories,
Category parentCategory,
List
- items,
Set categorizedItems,
Set categorizedItemComponents,
Map
- itemsAndUser) {
this.name = name;
this.childCategories = childCategories;
this.parentCategory = parentCategory;
this.items = items;
this.categorizedItems = categorizedItems;
this.categorizedItemComponents = categorizedItemComponents;
this.itemsAndUser = itemsAndUser;
}
/**
* Simple constructors
*/
public Category(String name) {
this.name = name;
}
public Category(String name, Category parentCategory) {
this.name = name;
this.parentCategory = parentCategory;
}
// ********************** Accessor Methods ********************** //
public Long getId() { return id; }
public int getVersion() { return version; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public List getChildCategories() { return childCategories; }
public void addChildCategory(Category childCategory) {
if (childCategory == null) throw new IllegalArgumentException("Null child category!");
if (childCategory.getParentCategory() != null)
childCategory.getParentCategory().getChildCategories().remove(childCategory);
childCategory.setParentCategory(parentCategory);
childCategories.add(childCategory);
}
public void removeChildCategory(Category childCategory) {
if (childCategory == null) throw new IllegalArgumentException("Null child category!");
childCategory.setParentCategory(null);
childCategories.remove(childCategory);
}
public Category getParentCategory() { return parentCategory; }
private void setParentCategory(Category parentCategory) { this.parentCategory = parentCategory; }
// Regular many-to-many
public List
- getItems() { return items; }
public void addItem(Item item) {
if (item == null) throw new IllegalArgumentException("Null item!");
items.add(item);
item.getCategories().add(this);
}
public void removeItem(Item item) {
if (item == null) throw new IllegalArgumentException("Null item!");
items.remove(item);
item.getCategories().remove(this);
}
// Many-to-many with additional columns on join table, intermediate entity class
// To create a link, instantiate a CategorizedItem with the right constructor
// To remove a link, use getCategorizedItems().remove()
public Set getCategorizedItems() { return categorizedItems; }
// Many-to-many with additional columns on join table, intermediate component class
public Set getCategorizedItemComponents() { return categorizedItemComponents; }
// Many-to-many with additional columns on join table, ternary hash map representation
public Map
- getItemsAndUser() { return itemsAndUser; }
public Date getCreated() { return created; }
// ********************** Common Methods ********************** //
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
final Category category = (Category) o;
if (!created.equals(category.created)) return false;
if (!name.equals(category.name)) return false;
return !(parentCategory != null ?
!parentCategory.equals(category.parentCategory) :
category.parentCategory != null);
}
public int hashCode() {
int result;
result = name.hashCode();
result = 29 * result + (parentCategory != null ? parentCategory.hashCode() : 0);
result = 29 * result + created.hashCode();
return result;
}
public int compareTo(Object o) {
if (o instanceof Category) {
return this.getName().compareTo( ((Category)o).getName() );
}
return 0;
}
public String toString() {
return "(" + getId() + ") Name: '" + getName();
}
// ********************** Business Methods ********************** //
}