package org.jboss.seam.wiki.core.dao;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.NoResultException;
import javax.persistence.Query;
import org.hibernate.Session;
import org.jboss.seam.Component;
import org.jboss.seam.annotations.AutoCreate;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.log.Log;
import org.jboss.seam.wiki.core.model.User;
import org.jboss.seam.wiki.core.model.WikiComment;
import org.jboss.seam.wiki.core.model.WikiDirectory;
import org.jboss.seam.wiki.core.model.WikiDocument;
import org.jboss.seam.wiki.core.model.WikiFile;
import org.jboss.seam.wiki.core.model.WikiMenuItem;
import org.jboss.seam.wiki.core.model.WikiNode;
import org.jboss.seam.wiki.core.model.WikiTreeNode;
import org.jboss.seam.wiki.core.model.WikiUpload;
/**
* DAO for nodes, transparently respects security access levels.
* <p>
* All node access should go through this component, this component knows
* about access levels because it relies on a restricted (filtered) Entitymanager.
*
* @author Christian Bauer
* @author Shane Bryzak
*
*/
@Name("wikiNodeDAO")
@AutoCreate
public class WikiNodeDAO {
@Logger
static Log log;
// Most of the DAO methods use this
@In protected EntityManager restrictedEntityManager;
// Some run unrestricted (e.g. internal unique key validation of wiki names)
// Make sure that these methods do not return detached objects!
@In
protected EntityManager entityManager;
public void makePersistent(WikiNode node) {
entityManager.persist(node);
}
public WikiNode findWikiNode(Long nodeId) {
try {
return (WikiNode) restrictedEntityManager
.createQuery("select n from WikiNode n where n.id = :id")
.setParameter("id", nodeId)
.setHint("org.hibernate.comment", "Find wikinode by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiNode> findWikiNodes(List<Long> ids) {
return restrictedEntityManager
.createQuery("select n from WikiNode n where n.id in (:idList)")
.setParameter("idList", ids)
.setHint("org.hibernate.comment", "Find wikinodes by id list")
.setHint("org.hibernate.cacheable", false)
.getResultList();
}
public WikiNode findWikiNodeInArea(Long areaNumber, String wikiname) {
return findWikiNodeInArea(areaNumber, wikiname, restrictedEntityManager);
}
public WikiNode findWikiNodeInArea(Long areaNumber, String wikiname, EntityManager em) {
try {
return (WikiNode) em
.createQuery("select n from WikiNode n where n.areaNumber = :areaNumber and n.wikiname = :wikiname")
.setParameter("areaNumber", areaNumber)
.setParameter("wikiname", wikiname)
.setHint("org.hibernate.comment", "Find node in area")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public Long findChildrenCount(WikiNode node) {
try {
return (Long) restrictedEntityManager
.createQuery("select count(n) from WikiNode n where n.parent = :parent")
.setParameter("parent", node)
.setHint("org.hibernate.comment", "Find number of wikinode children")
.setHint("org.hibernate.cacheable", true)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiNode> findChildren(WikiNode node, WikiNode.SortableProperty orderBy,
boolean orderAscending, int firstResult, int maxResults) {
StringBuilder queryString = new StringBuilder();
queryString.append("select n from WikiNode n where n.parent = :parent").append(" ");
queryString.append("order by n.").append(orderBy.name()).append(" ").append(orderAscending ? "asc" : "desc");
Query query = restrictedEntityManager
.createQuery(queryString.toString())
.setHint("org.hibernate.comment", "Find wikinode children order by "+orderBy.name())
.setParameter("parent", node)
.setHint("org.hibernate.cacheable", false)
.setFirstResult(firstResult);
if (maxResults > 0)
{
query.setMaxResults(maxResults);
}
return query.getResultList();
}
public List<WikiNode> findWikiNodes(User user)
{
return restrictedEntityManager.createQuery("select n from WikiNode n where n.createdBy = :createdBy")
.setParameter("createdBy", user)
.getResultList();
}
@SuppressWarnings("unchecked")
public List<WikiDirectory> findChildWikiDirectories(WikiDirectory dir) {
return restrictedEntityManager
.createQuery("select d from WikiDirectory d left join fetch d.feed where d.parent = :parent")
.setHint("org.hibernate.comment", "Find wikinode children directories")
.setParameter("parent", dir)
.setHint("org.hibernate.cacheable", false)
.getResultList();
}
public WikiComment findWikiComment(Long commentId) {
try {
return (WikiComment) restrictedEntityManager
.createQuery("select c from WikiComment c where c.id = :id")
.setParameter("id", commentId)
.setHint("org.hibernate.comment", "Find comment by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiComment> findWikiComments(WikiDocument document, boolean orderbyDateAscending) {
String query =
"select c from WikiComment c where c.parent = :parentDoc order by c.createdOn " +
(orderbyDateAscending ? "asc" : "desc");
return (List<WikiComment>)restrictedEntityManager
.createQuery(query)
.setParameter("parentDoc", document)
.setHint("org.hibernate.comment", "Finding all comments of document")
.getResultList();
}
/**
* Returns a list of all the WikiComments created by a particular user
* @param createdBy
* @return
*/
@SuppressWarnings("unchecked")
public List<WikiComment> findWikiComments(User createdBy)
{
return (List<WikiComment>) restrictedEntityManager.createQuery(
"select c from WikiComment c where c.createdBy = :createdBy")
.setParameter("createdBy", createdBy)
.getResultList();
}
/**
* Returns a list of all the WikiComments matching the specified parameters
*
* @param fromUserName
* @param fromUserEmail
* @param fromUserHomepage
* @return
*/
@SuppressWarnings("unchecked")
public List<WikiComment> findWikiComments(String fromUserName, String fromUserEmail,
String fromUserHomepage)
{
if (fromUserName == null && fromUserEmail == null && fromUserHomepage == null)
{
throw new IllegalArgumentException("At least one parameter must be not null.");
}
StringBuilder criteria = new StringBuilder();
if (fromUserName != null)
{
criteria.append("where c.fromUserName = :fromUserName");
}
if (fromUserEmail != null)
{
if (criteria.length() > 0) criteria.append(" and ");
criteria.append("c.fromUserEmail = :fromUserEmail");
}
if (fromUserHomepage != null)
{
if (criteria.length() > 0) criteria.append(" and ");
criteria.append("c.fromUserHomepage = :fromUserHomepage");
}
Query query = restrictedEntityManager.createQuery("select c from WikiComment c " + criteria.toString());
if (fromUserName != null) query.setParameter("fromUserName", fromUserName);
if (fromUserEmail != null) query.setParameter("fromUserEmail", fromUserEmail);
if (fromUserHomepage != null) query.setParameter("fromUserHomepage", fromUserHomepage);
return (List<WikiComment>) query.getResultList();
}
public WikiFile findWikiFile(Long fileId) {
try {
return (WikiFile) restrictedEntityManager
.createQuery("select f from WikiFile f where f.id = :id")
.setParameter("id", fileId)
.setHint("org.hibernate.comment", "Find wikifile by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public WikiFile findWikiFileInArea(Long areaNumber, String wikiname) {
return findWikiFileInArea(areaNumber, wikiname, restrictedEntityManager);
}
public WikiFile findWikiFileInArea(Long areaNumber, String wikiname, EntityManager em) {
try {
return (WikiFile) em
.createQuery("select f from WikiFile f where f.areaNumber = :areaNumber and f.wikiname = :wikiname")
.setParameter("areaNumber", areaNumber)
.setParameter("wikiname", wikiname)
.setHint("org.hibernate.comment", "Find wikifile in area")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public WikiDocument findWikiDocument(Long documentId) {
try {
return (WikiDocument) restrictedEntityManager
.createQuery("select d from WikiDocument d where d.id = :id")
.setParameter("id", documentId)
.setHint("org.hibernate.comment", "Find document by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
// Access restricted version of directory.getDefaultFile()
public WikiFile findDefaultWikiFile(WikiDirectory directory) {
if (directory == null) return null;
try {
return (WikiFile) restrictedEntityManager
.createQuery("select d.defaultFile from WikiDirectory d where d = :dir")
.setParameter("dir", directory)
.setHint("org.hibernate.comment", "Find default file")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
// Access restricted version of directory.getDefaultFile(), also narrows it down to a document (see WikiRequestResolver)
public WikiDocument findDefaultDocument(WikiDirectory directory) {
if (directory == null) return null;
try {
return (WikiDocument) restrictedEntityManager
.createQuery("select doc from WikiDocument doc, WikiDirectory d where d = :dir and doc.id = d.defaultFile.id")
.setParameter("dir", directory)
.setHint("org.hibernate.comment", "Find default doc")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiDocument> findWikiDocuments(WikiDirectory directory, WikiNode.SortableProperty orderBy, boolean orderAscending) {
StringBuilder query = new StringBuilder();
query.append("select d from WikiDocument d where d.parent = :dir");
query.append(" order by d.").append(orderBy.name()).append(" ").append(orderAscending ? "asc" : "desc");
return restrictedEntityManager.createQuery(query.toString())
.setParameter("dir", directory)
.setHint("org.hibernate.comment", "Find documents of directory")
.setHint("org.hibernate.cacheable", false)
.getResultList();
}
public WikiDocument findWikiDocumentInArea(Long areaNumber, String wikiname) {
return findWikiDocumentInArea(areaNumber, wikiname, restrictedEntityManager);
}
public WikiDocument findWikiDocumentInArea(Long areaNumber, String wikiname, EntityManager em) {
try {
return (WikiDocument) em
.createQuery("select d from WikiDocument d where d.areaNumber = :areaNumber and d.wikiname = :wikiname")
.setParameter("areaNumber", areaNumber)
.setParameter("wikiname", wikiname)
.setHint("org.hibernate.comment", "Find document in area")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiDocument> findWikiDocuments(int maxResults, WikiNode.SortableProperty orderBy, boolean orderAscending) {
StringBuilder query = new StringBuilder();
query.append("select d from WikiDocument d where d.").append(orderBy.name()).append(" is not null");
query.append(" order by d.").append(orderBy.name()).append(" ").append(orderAscending ? "asc" : "desc");
return (List<WikiDocument>)restrictedEntityManager
.createQuery(query.toString())
.setHint("org.hibernate.comment", "Find documents order by " + orderBy.name())
.setHint("org.hibernate.cacheable", false)
.setMaxResults(maxResults)
.getResultList();
}
public WikiDocument findSiblingWikiDocumentInDirectory(WikiDocument currentDocument, WikiNode.SortableProperty byProperty, boolean previousOrNext) {
try {
return (WikiDocument)restrictedEntityManager
.createQuery("select sibling from WikiDocument sibling, WikiDocument current" +
" where sibling.parent = current.parent and current = :current and not sibling = :current" +
" and sibling."+ byProperty.name() + " " + (previousOrNext ? "<=" : ">=") + "current."+ byProperty.name() +
" order by sibling." +byProperty + " " + (previousOrNext ? "desc" : "asc") )
.setHint("org.hibernate.cacheable", false)
.setMaxResults(1)
.setParameter("current", currentDocument)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public WikiUpload findWikiUpload(Long uploadId) {
try {
return (WikiUpload) restrictedEntityManager
.createQuery("select u from WikiUpload u where u.id = :id")
.setParameter("id", uploadId)
.setHint("org.hibernate.comment", "Find upload by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
@SuppressWarnings("unchecked")
public List<WikiUpload> findWikiUploads(WikiDirectory directory, WikiNode.SortableProperty orderBy, boolean orderAscending) {
StringBuilder query = new StringBuilder();
query.append("select u from WikiUpload u where u.parent = :dir");
query.append(" order by u.").append(orderBy.name()).append(" ").append(orderAscending ? "asc" : "desc");
return restrictedEntityManager.createQuery(query.toString())
.setParameter("dir", directory)
.setHint("org.hibernate.comment", "Find uploads of directory")
.setHint("org.hibernate.cacheable", false)
.getResultList();
}
public WikiDirectory findWikiDirectory(Long directoryId) {
try {
return (WikiDirectory) restrictedEntityManager
.createQuery("select d from WikiDirectory d left join fetch d.feed where d.id = :id")
.setParameter("id", directoryId)
.setHint("org.hibernate.comment", "Find directory by id")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public User findWikiDirectoryMemberHome(Long directoryId) {
try {
return (User) restrictedEntityManager
.createQuery("select u from User u where u.memberHome.id = :id")
.setParameter("id", directoryId)
.setHint("org.hibernate.comment", "Find user for directory member home by id")
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public WikiDirectory findWikiDirectoryInAreaUnrestricted(Long areaNumber, String wikiname) {
return findWikiDirectoryInArea(areaNumber, wikiname, entityManager);
}
public WikiDirectory findWikiDirectoryInArea(Long areaNumber, String wikiname) {
return findWikiDirectoryInArea(areaNumber, wikiname, restrictedEntityManager);
}
public WikiDirectory findWikiDirectoryInArea(Long areaNumber, String wikiname, EntityManager em) {
try {
return (WikiDirectory) em
.createQuery("select d from WikiDirectory d left join fetch d.feed where d.areaNumber = :areaNumber and d.wikiname = :wikiname")
.setParameter("areaNumber", areaNumber)
.setParameter("wikiname", wikiname)
.setHint("org.hibernate.comment", "Find directory in area")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public List<Long> findWikiDirectoryTreeIDs(WikiDirectory startDir) {
List<Long> parentDirIds = new ArrayList();
List<WikiTreeNode<WikiDirectory>> directoryTree = findWikiDirectoryTree(startDir, WikiNode.SortableProperty.createdOn, true);
for (WikiTreeNode<WikiDirectory> treeNode : directoryTree) {
parentDirIds.add(treeNode.getNode().getId());
}
return parentDirIds;
}
public List<WikiTreeNode<WikiDirectory>> findWikiDirectoryTree(WikiDirectory rootDir, WikiNode.SortableProperty sortByProperty, boolean sortAscending) {
List<WikiTreeNode<WikiDirectory>> tree = new ArrayList();
long level = 1;
tree.add(new WikiTreeNode<WikiDirectory>(level++, rootDir));
String query = "select d from WikiDirectory d where d.parent.id = :parentNodeId and d.readAccessLevel <= :readAccessLevel order by " +
sortByProperty.name() + " " + (sortAscending ? "asc" : "desc");
appendWikiNodeChildren(query, tree, rootDir.getId(), level, null, null);
return tree;
}
public List<WikiTreeNode<WikiDirectory>> findMenuItemTree(WikiDirectory rootDir, Long maxDepth, Long flattenToLevel, boolean onlyCreatedByAdminUser) {
List<WikiTreeNode<WikiDirectory>> tree = new ArrayList();
long level = 1;
// TODO: Root in or out?
// tree.add(new WikiTreeNode<WikiDirectory>(level++, rootDir));
String query = "select d from WikiMenuItem mi join mi.directory d" +
" where d.parent.id = :parentNodeId" +
" and d.readAccessLevel <= :readAccessLevel" +
(onlyCreatedByAdminUser ? " and d.createdBy.id = '"+((User)Component.getInstance("adminUser")).getId()+"'" : "") +
" order by mi.displayPosition asc";
appendWikiNodeChildren(query, tree, rootDir.getId(), level, maxDepth, flattenToLevel);
return tree;
}
// Recursive! Don't use for large trees...
@SuppressWarnings("unchecked")
private void appendWikiNodeChildren(String query, List tree, long parentNodeId, long currentLevel, Long maxDepth, Long flattenToLevel) {
List<WikiNode> nodes = restrictedEntityManager.createQuery(query)
.setHint("org.hibernate.comment", "Querying children of wiki node: " + parentNodeId)
.setParameter("parentNodeId", parentNodeId)
.setParameter("readAccessLevel", Component.getInstance("currentAccessLevel"))
.getResultList();
for (WikiNode node : nodes) {
tree.add(new WikiTreeNode(currentLevel, node));
if (maxDepth == null || currentLevel < maxDepth) {
if (flattenToLevel == null || currentLevel < flattenToLevel) {
currentLevel++;
appendWikiNodeChildren(query, tree, node.getId(), currentLevel, maxDepth, flattenToLevel);
currentLevel--;
} else {
appendWikiNodeChildren(query, tree, node.getId(), currentLevel, maxDepth, flattenToLevel);
}
}
}
}
public WikiDirectory findAreaUnrestricted(String wikiname) {
return findArea(wikiname, entityManager);
}
public WikiDirectory findArea(String wikiname) {
return findArea(wikiname, restrictedEntityManager);
}
public WikiDirectory findArea(String wikiname, EntityManager em) {
try {
return (WikiDirectory) em
.createQuery("select d from WikiDirectory d left join fetch d.feed, WikiDirectory r where r.parent is null and d.parent = r and d.wikiname = :wikiname")
.setParameter("wikiname", wikiname)
.setHint("org.hibernate.comment", "Find area by wikiname")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public WikiDirectory findArea(Long areaNumber) {
try {
return (WikiDirectory) restrictedEntityManager
.createQuery("select d from WikiDirectory d left join fetch d.feed, WikiDirectory r where r.parent is null and d.parent = r and d.areaNumber = :areaNumber")
.setParameter("areaNumber", areaNumber)
.setHint("org.hibernate.comment", "Find area by area number")
.setHint("org.hibernate.cacheable", false)
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
// TODO: This method is a mess...
// Returns a detached object
public WikiDocument findHistoricalDocumentAndDetach(String entityName, Long historyId) {
// Initialize bytecode-enhanced fields with 'fetch all properties'!
log.debug("fetching WikiFile historical revision with id: " + historyId + " and initializing all properties");
WikiDocument historicalFile = (WikiDocument)
getSession(true).createQuery("select f from " + entityName + " f fetch all properties where f.historicalFileId = :id")
.setParameter("id", historyId)
.uniqueResult();
if (historicalFile != null) {
historicalFile.getContent(); // TODO: the fetch all properties doesn't work for some reason..
getSession(true).evict(historicalFile);
return historicalFile;
} else {
return null;
}
}
public List<WikiFile> findHistoricalFiles(WikiFile file) {
if (file == null || file.getId() == null) return null;
return getSession(true).createQuery("select f from " + file.getHistoricalEntityName() + " f where f.id = :fileId order by f.revision desc")
.setParameter("fileId", file.getId())
.list();
}
public Long findNumberOfHistoricalFiles(WikiFile file) {
if (file == null || file.getId() == null) return 0l;
return (Long)getSession(true).createQuery("select count(f) from " + file.getHistoricalEntityName() + " f where f.id = :fileId")
.setParameter("fileId", file.getId())
.setCacheable(true)
.uniqueResult();
}
public void persistHistoricalFile(WikiFile historicalFile) {
if (historicalFile.getHistoricalEntityName() != null) {
log.debug("persisting historical file: " + historicalFile + " as revision: " + historicalFile.getRevision());
// Use the nonrestricted persistence context, which should be safe here so we can flush it again
// TODO: I wish Hibernate/JBoss weren't so retarted about getting a StatelessSession when you need one...
getSession(false).persist(historicalFile.getHistoricalEntityName(), historicalFile);
getSession(false).flush();
getSession(false).evict(historicalFile);
}
}
public void removeHistoricalFiles(WikiFile file) {
if (file == null || file.getId() == null) return;
((WikiFile)getSession(true).load(WikiFile.class, file.getId())).setRevision(0);
getSession(true).flush();
getSession(true).createQuery("delete from " + file.getHistoricalEntityName() + " f where f.id = :fileId")
.setParameter("fileId", file.getId())
.executeUpdate();
}
// Multi-row constraint validation
public boolean isUniqueWikiname(Long areaNumber, WikiNode node) {
WikiNode foundNode = findWikiNodeInArea(areaNumber, node.getWikiname(), entityManager);
return foundNode == null || node.getId() != null && node.getId().equals(foundNode.getId());
}
public boolean isUniqueWikiname(Long areaNumber, String wikiname) {
WikiNode foundNode = findWikiNodeInArea(areaNumber, wikiname, entityManager);
return foundNode == null;
}
public WikiMenuItem findMenuItem(WikiDirectory dir) {
try {
return (WikiMenuItem) restrictedEntityManager
.createQuery("select m from WikiMenuItem m where m.directory = :dir")
.setParameter("dir", dir)
.setHint("org.hibernate.comment", "Find menu item of directory")
.getSingleResult();
} catch (EntityNotFoundException ignored) {
} catch (NoResultException ignored) {
}
return null;
}
public List<WikiMenuItem> findMenuItems(WikiDirectory parentDir) {
return restrictedEntityManager.createQuery("select m from WikiMenuItem m where m.directory.parent = :parent order by m.displayPosition asc")
.setParameter("parent", parentDir)
.getResultList();
}
private Session getSession(boolean restricted) {
if (restricted) {
return ((Session)((org.jboss.seam.persistence.EntityManagerProxy) restrictedEntityManager).getDelegate());
} else {
return ((Session)((org.jboss.seam.persistence.EntityManagerProxy) entityManager).getDelegate());
}
}
public static WikiNodeDAO instance() {
return (WikiNodeDAO)Component.getInstance(WikiNodeDAO.class);
}
}