package org.jboss.seam.wiki.core.model;
import org.hibernate.validator.Pattern;
import org.hibernate.validator.Length;
import org.hibernate.validator.Range;
import org.jboss.seam.wiki.core.search.annotations.Searchable;
import org.jboss.seam.wiki.core.search.annotations.SearchableType;
import org.jboss.seam.wiki.core.search.PaddedIntegerBridge;
import javax.persistence.*;
import java.util.Date;
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(
name = "WIKI_NODE",
uniqueConstraints = {
// Wikiname of a document needs to be unique within an area
@UniqueConstraint(columnNames = {"AREA_NR", "WIKINAME"})
}
)
@org.hibernate.annotations.Filter(
name = "accessLevelFilter",
condition = "READ_ACCESS_LEVEL <= :currentAccessLevel"
)
@org.hibernate.annotations.BatchSize(size = 20)
public abstract class WikiNode<N extends WikiNode> implements Comparable {
public static enum SortableProperty {
name, createdOn, createdBy, lastModifiedOn, lastModifiedBy, rating
}
@Id
@GeneratedValue(generator = "wikiSequenceGenerator")
@Column(name = "NODE_ID")
@org.hibernate.search.annotations.DocumentId(name = "nodeId")
protected Long id;
@Version
@Column(name = "OBJ_VERSION", nullable = false)
protected int version = 0;
@Column(name = "AREA_NR", nullable = false)
protected Long areaNumber;
@Column(name = "NAME", length = 255, nullable = false)
@Length(min = 3, max = 255)
@Pattern(
regex="^[a-zA-Z0-9]+[^/#\\|\\]\\[]*",
message="#{messages['lacewiki.entity.NameMustStartWithLetterOrNumber']}"
)
protected String name;
@Column(name = "WIKINAME", length = 255, nullable = false)
@Pattern(
regex="^[A-Z0-9]+.*",
message="#{messages['lacewiki.entity.NameMustStartWithUppercaseLetterOrNumber']}"
)
protected String wikiname;
@Column(name = "MESSAGE_ID", length = 1023, nullable = true)
protected String messageId;
@Column(name = "CREATED_ON", nullable = false, updatable = false)
@org.hibernate.search.annotations.Field(
index = org.hibernate.search.annotations.Index.UN_TOKENIZED,
store = org.hibernate.search.annotations.Store.YES
)
@org.hibernate.search.annotations.DateBridge(resolution = org.hibernate.search.annotations.Resolution.DAY)
@Searchable(description = "Created", type = SearchableType.PASTDATE)
protected Date createdOn = new Date();
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "CREATED_BY_USER_ID", nullable = false)
@org.hibernate.annotations.ForeignKey(name = "FK_WIKI_NODE_CREATED_BY_USER_ID")
protected User createdBy;
@Column(name = "LAST_MODIFIED_ON", nullable = true)
@org.hibernate.search.annotations.Field(
index = org.hibernate.search.annotations.Index.UN_TOKENIZED,
store = org.hibernate.search.annotations.Store.YES
)
@org.hibernate.search.annotations.DateBridge(resolution = org.hibernate.search.annotations.Resolution.DAY)
@Searchable(description = "Last Modified", type = SearchableType.PASTDATE)
protected Date lastModifiedOn;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "LAST_MODIFIED_BY_USER_ID", nullable = true)
@org.hibernate.annotations.ForeignKey(name = "FK_WIKI_NODE_LAST_MODIFIED_BY")
protected User lastModifiedBy;
@Column(name = "WRITE_ACCESS_LEVEL", nullable = false)
protected int writeAccessLevel = 0;
@Column(name = "READ_ACCESS_LEVEL", nullable = false)
@org.hibernate.search.annotations.Field(
index = org.hibernate.search.annotations.Index.UN_TOKENIZED,
store = org.hibernate.search.annotations.Store.YES
)
@org.hibernate.search.annotations.FieldBridge(impl = PaddedIntegerBridge.class)
protected int readAccessLevel = 0;
@Column(name = "WRITE_PROTECTED", nullable = false)
protected boolean writeProtected = false;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "PARENT_NODE_ID", nullable = true)
//TODO: @org.hibernate.annotations.OnDelete(action = org.hibernate.annotations.OnDeleteAction.CASCADE)
@org.hibernate.annotations.ForeignKey(name = "FK_WIKI_NODE_PARENT_NODE_ID")
@org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.JOIN)
protected WikiNode parent;
@Range(min = 0l, max = 5)
@Column(name = "RATING", nullable = false)
private int rating = 0;
protected WikiNode() {}
protected WikiNode(String name) {
this.name = name;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public Long getAreaNumber() { return areaNumber; }
public void setAreaNumber(Long areaNumber) { this.areaNumber = areaNumber; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getWikiname() { return wikiname; }
public void setWikiname(String wikiname) { this.wikiname = wikiname; }
public String getMessageId() { return messageId; }
public void setMessageId(String messageId) { this.messageId = messageId; }
public Date getCreatedOn() { return createdOn; }
public void setCreatedOn(Date createdOn) { this.createdOn = createdOn; }
public User getCreatedBy() { return createdBy; }
public void setCreatedBy(User createdBy) { this.createdBy = createdBy; }
public Date getLastModifiedOn() { return lastModifiedOn; }
public void setLastModifiedOn(Date lastModifiedOn) { this.lastModifiedOn = lastModifiedOn; }
public User getLastModifiedBy() { return lastModifiedBy; }
public void setLastModifiedBy(User lastModifiedBy) { this.lastModifiedBy = lastModifiedBy; }
public int getWriteAccessLevel() { return writeAccessLevel; }
public void setWriteAccessLevel(int writeAccessLevel) { this.writeAccessLevel = writeAccessLevel; }
public int getReadAccessLevel() { return readAccessLevel; }
public void setReadAccessLevel(int readAccessLevel) { this.readAccessLevel = readAccessLevel; }
public boolean isWriteProtected() { return writeProtected; }
public void setWriteProtected(boolean writeProtected) { this.writeProtected = writeProtected; }
public WikiNode getParent() { return parent; }
public void setParent(WikiNode parent) { this.parent = parent; }
public int getRating() { return rating; }
public void setRating(int rating) { this.rating = rating; }
public WikiNode getArea() {
if (this.getParent() != null && this.getParent().getParent() == null) return this; // This is an area
// Else, walk up the tree until we find the area
WikiNode current = this.getParent();
while (current != null && current.getParent() != null && current.getParent().getParent() != null) {
current = current.getParent();
}
return current; // Return null if this is the Wiki ROOT
}
public int compareTo(Object o) {
return getName().compareTo( ((WikiNode)o).getName());
}
/**
* Creates copy for display or history archiving.
* <p>
* Does <b>NOT</b> copy the node id and object version, so the copy might as well be
* considered transient and can be persisted right away. If you want to store the
* copy in the audit log, call setId() manually before on the copy, passing in the
* identifier value of the original. Note that no collections or entity association
* (many-to-one, one-to-one) references are copied!
* </p>
* @param original The node to make a copy of
* @param copyLazyProperties Copy (potentially large) properties which are lazily loaded
*/
public void flatCopy(WikiNode original, boolean copyLazyProperties) {
this.areaNumber = original.getAreaNumber();
this.name = original.name;
this.wikiname = original.wikiname;
this.lastModifiedOn = original.lastModifiedOn;
this.writeAccessLevel = original.writeAccessLevel;
this.readAccessLevel = original.readAccessLevel;
}
// Need this for JSF EL expressions
public boolean isInstance(String className) {
try {
Class clazz = Class.forName(getClass().getPackage().getName() + "." + className);
return isInstance(clazz);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
public boolean isInstance(Class clazz) {
return clazz.isAssignableFrom(this.getClass());
}
public boolean isOwnedByRegularUser() {
return getCreatedBy() != null
&& !User.ADMIN_USERNAME.equals(getCreatedBy().getUsername())
&& !User.GUEST_USERNAME.equals(getCreatedBy().getUsername());
}
public abstract String getPermURL(String suffix);
public abstract String getWikiURL();
public abstract N duplicate(boolean copyLazyProperties);
}